1
0
mirror of https://github.com/Unleash/unleash.git synced 2024-12-22 19:07:54 +01:00

docs: Auth tag (#4126)

## What
This adds openapi documentation for the Auth tagged operations and
connected schemas.

## Discussion points
Our user schema seems to be exposing quite a bit of internal fields, I
flagged the isApi field as deprecated, I can imagine quite a few of
these fields also being deprecated to prepare for removal in next major
version, but I was unsure which ones were safe to do so with.

## Observation
We have some technical debt around the shape of the schema we're
claiming we're returning and what we actually are returning. I believe
@gastonfournier also observed this when we turned on validation for our
endpoints.

---------

Co-authored-by: Thomas Heartman <thomas@getunleash.ai>
This commit is contained in:
Christopher Kolstad 2023-07-04 10:31:54 +02:00 committed by GitHub
parent 95a02158e8
commit 0b18491237
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 518 additions and 37 deletions

View File

@ -92,13 +92,11 @@ const metaRules: Rule[] = [
knownExceptions: [
'batchFeaturesSchema',
'batchStaleSchema',
'changePasswordSchema',
'cloneFeatureSchema',
'createApiTokenSchema',
'createFeatureSchema',
'createInvitedUserSchema',
'createUserSchema',
'emailSchema',
'environmentsSchema',
'environmentsProjectSchema',
'eventSchema',
@ -118,7 +116,6 @@ const metaRules: Rule[] = [
'groupsSchema',
'groupUserModelSchema',
'idSchema',
'loginSchema',
'maintenanceSchema',
'toggleMaintenanceSchema',
'meSchema',
@ -135,7 +132,6 @@ const metaRules: Rule[] = [
'pushVariantsSchema',
'resetPasswordSchema',
'requestsPerSecondSchema',
'roleSchema',
'sdkContextSchema',
'searchEventsSchema',
'setUiConfigSchema',
@ -145,7 +141,6 @@ const metaRules: Rule[] = [
'tagTypeSchema',
'tagTypesSchema',
'tagWithVersionSchema',
'tokenUserSchema',
'uiConfigSchema',
'updateApiTokenSchema',
'updateFeatureSchema',
@ -154,11 +149,9 @@ const metaRules: Rule[] = [
'updateUserSchema',
'upsertContextFieldSchema',
'upsertStrategySchema',
'userSchema',
'usersGroupsBaseSchema',
'usersSchema',
'validateEdgeTokensSchema',
'validatePasswordSchema',
'validateTagTypeSchema',
'variantFlagSchema',
'versionSchema',
@ -183,7 +176,6 @@ const metaRules: Rule[] = [
'applicationsSchema',
'batchFeaturesSchema',
'batchStaleSchema',
'changePasswordSchema',
'cloneFeatureSchema',
'createApiTokenSchema',
'createFeatureSchema',
@ -191,7 +183,6 @@ const metaRules: Rule[] = [
'createInvitedUserSchema',
'createUserSchema',
'dateSchema',
'emailSchema',
'environmentsSchema',
'eventSchema',
'eventsSchema',
@ -209,7 +200,6 @@ const metaRules: Rule[] = [
'groupsSchema',
'groupUserModelSchema',
'idSchema',
'loginSchema',
'maintenanceSchema',
'toggleMaintenanceSchema',
'meSchema',
@ -229,7 +219,6 @@ const metaRules: Rule[] = [
'resetPasswordSchema',
'requestsPerSecondSchema',
'requestsPerSecondSegmentedSchema',
'roleSchema',
'setStrategySortOrderSchema',
'setUiConfigSchema',
'sortOrderSchema',
@ -238,7 +227,6 @@ const metaRules: Rule[] = [
'tagTypeSchema',
'tagTypesSchema',
'tagWithVersionSchema',
'tokenUserSchema',
'uiConfigSchema',
'updateApiTokenSchema',
'updateFeatureSchema',
@ -247,12 +235,10 @@ const metaRules: Rule[] = [
'updateUserSchema',
'upsertContextFieldSchema',
'upsertStrategySchema',
'userSchema',
'usersGroupsBaseSchema',
'usersSchema',
'usersSearchSchema',
'validateEdgeTokensSchema',
'validatePasswordSchema',
'validateTagTypeSchema',
'variantFlagSchema',
'variantsSchema',

View File

@ -5,12 +5,19 @@ export const changePasswordSchema = {
type: 'object',
additionalProperties: false,
required: ['token', 'password'],
description: 'Change password as long as the token is a valid token',
properties: {
token: {
description:
'A reset token used to validate that the user is allowed to change the password.',
type: 'string',
example:
'$2a$15$QzeW/y5/MEppCWVEkoX5euejobYOLSd4We21LQjjKlWH9l2I3wCke',
},
password: {
type: 'string',
description: 'The new password for the user',
example: 'correct horse battery staple',
},
},
components: {},

View File

@ -5,9 +5,13 @@ export const emailSchema = {
type: 'object',
additionalProperties: false,
required: ['email'],
description:
'Represents the email of a user. Used to send email communication (reset password, welcome mail etc)',
properties: {
email: {
description: 'The email address',
type: 'string',
example: 'test@example.com',
},
},
components: {},

View File

@ -5,12 +5,17 @@ export const loginSchema = {
type: 'object',
additionalProperties: false,
required: ['username', 'password'],
description: 'A username/password login request',
properties: {
username: {
description: 'The username trying to log in',
type: 'string',
example: 'user',
},
password: {
description: 'The password of the user trying to log in',
type: 'string',
example: 'hunter2',
},
},
components: {},

View File

@ -3,20 +3,32 @@ import { FromSchema } from 'json-schema-to-ts';
export const roleSchema = {
$id: '#/components/schemas/roleSchema',
type: 'object',
description:
'A role holds permissions to allow Unleash to decide what actions a role holder is allowed to perform',
additionalProperties: false,
required: ['id', 'type', 'name'],
properties: {
id: {
type: 'number',
type: 'integer',
description: 'The role id',
example: 9,
minimum: 0,
},
type: {
description:
'A role can either be a global role (applies to all projects) or a project role',
type: 'string',
example: 'global',
},
name: {
description: `The name of the role`,
type: 'string',
example: 'Editor',
},
description: {
description: `A more detailed description of the role and what use it's intended for`,
type: 'string',
example: `Users with the editor role have access to most features in Unleash but can not manage users and roles in the global scope. Editors will be added as project owners when creating projects and get superuser rights within the context of these projects. Users with the editor role will also get access to most permissions on the default project by default.`,
},
},
components: {},

View File

@ -5,23 +5,35 @@ export const tokenUserSchema = {
$id: '#/components/schemas/tokenUserSchema',
type: 'object',
additionalProperties: false,
description: 'A user identified by a token',
required: ['id', 'name', 'email', 'token', 'createdBy', 'role'],
properties: {
id: {
type: 'number',
type: 'integer',
description: 'The user id',
example: 7,
},
name: {
description: 'The name of the user',
type: 'string',
example: 'Test McTest',
},
email: {
description: 'The email of the user',
type: 'string',
example: 'test@example.com',
},
token: {
description: 'A token uniquely identifying a user',
type: 'string',
example: 'user:xyzrandomstring',
},
createdBy: {
description:
'A username or email identifying which user created this token',
type: 'string',
nullable: true,
example: 'admin@example.com',
},
role: {
$ref: '#/components/schemas/roleSchema',

View File

@ -5,50 +5,84 @@ export const userSchema = {
$id: '#/components/schemas/userSchema',
type: 'object',
additionalProperties: false,
description: 'An Unleash user',
required: ['id'],
properties: {
id: {
type: 'number',
description: 'The user id',
type: 'integer',
minimum: 0,
example: 123,
},
isAPI: {
description:
'(Deprecated): Used internally to know which operations the user should be allowed to perform',
type: 'boolean',
example: true,
deprecated: true,
},
name: {
description: 'Name of the user',
type: 'string',
example: 'User',
},
email: {
description: 'Email of the user',
type: 'string',
example: 'user@example.com',
},
username: {
description: 'A unique username for the user',
type: 'string',
example: 'hunter',
},
imageUrl: {
description: `URL used for the userprofile image`,
type: 'string',
example: 'https://example.com/242x200.png',
},
inviteLink: {
description: `If the user is actively inviting other users, this is the link that can be shared with other users`,
type: 'string',
example: 'http://localhost:4242/invite-link/some-secret',
},
loginAttempts: {
type: 'number',
description:
'How many unsuccessful attempts at logging in has the user made',
type: 'integer',
minimum: 0,
example: 3,
},
emailSent: {
description: 'Is the welcome email sent to the user or not',
type: 'boolean',
example: false,
},
rootRole: {
type: 'number',
description:
'Which [root role](https://docs.getunleash.io/reference/rbac#standard-roles) this user is assigned',
type: 'integer',
example: 1,
minimum: 0,
},
seenAt: {
description: 'The last time this user logged in',
type: 'string',
format: 'date-time',
nullable: true,
example: '2023-06-30T11:42:00.345Z',
},
createdAt: {
description: 'The user was created at this time',
type: 'string',
format: 'date-time',
example: '2023-06-30T11:41:00.123Z',
},
accountType: {
description: 'A user is either an actual User or a Service Account',
type: 'string',
enum: AccountTypes,
example: 'User',
},
},
components: {},

View File

@ -5,9 +5,13 @@ export const validatePasswordSchema = {
type: 'object',
additionalProperties: false,
required: ['password'],
description:
'Used to validate passwords obeying [Unleash password guidelines](https://docs.getunleash.io/reference/deploy/securing-unleash#password-requirements)',
properties: {
password: {
description: 'The password to validate',
type: 'string',
example: 'hunter2',
},
},
components: {},

View File

@ -13,7 +13,10 @@ import {
TokenUserSchema,
} from '../../openapi/spec/token-user-schema';
import { EmailSchema } from '../../openapi/spec/email-schema';
import { emptyResponse } from '../../openapi/util/standard-responses';
import {
emptyResponse,
getStandardResponses,
} from '../../openapi/util/standard-responses';
interface IValidateQuery {
token: string;
@ -56,9 +59,15 @@ class ResetPasswordController extends Controller {
permission: NONE,
middleware: [
openApiService.validPath({
summary: 'Validates a token',
description:
'If the token is valid returns the user that owns the token',
tags: ['Auth'],
operationId: 'validateToken',
responses: { 200: createResponseSchema('tokenUserSchema') },
responses: {
200: createResponseSchema('tokenUserSchema'),
...getStandardResponses(401, 415),
},
}),
],
});
@ -70,9 +79,15 @@ class ResetPasswordController extends Controller {
middleware: [
openApiService.validPath({
tags: ['Auth'],
summary: `Changes a user password`,
description:
'Allows users with a valid reset token to reset their password without remembering their old password',
operationId: 'changePassword',
requestBody: createRequestSchema('changePasswordSchema'),
responses: { 200: emptyResponse },
responses: {
200: emptyResponse,
...getStandardResponses(401, 403, 415),
},
}),
],
});
@ -84,9 +99,15 @@ class ResetPasswordController extends Controller {
middleware: [
openApiService.validPath({
tags: ['Auth'],
summary: 'Validates password',
description:
'Verifies that the password adheres to the [Unleash password guidelines](https://docs.getunleash.io/reference/deploy/securing-unleash#password-requirements)',
operationId: 'validatePassword',
requestBody: createRequestSchema('validatePasswordSchema'),
responses: { 200: emptyResponse },
responses: {
200: emptyResponse,
...getStandardResponses(400, 415),
},
}),
],
});
@ -98,9 +119,15 @@ class ResetPasswordController extends Controller {
middleware: [
openApiService.validPath({
tags: ['Auth'],
summary: 'Reset password',
description:
'Requests a password reset email for the user. This email can be used to reset the password for a user that has forgotten their password',
operationId: 'sendResetPasswordEmail',
requestBody: createRequestSchema('emailSchema'),
responses: { 200: emptyResponse },
responses: {
200: emptyResponse,
...getStandardResponses(401, 404, 415),
},
}),
],
});

View File

@ -12,6 +12,7 @@ import { createResponseSchema } from '../../openapi/util/create-response-schema'
import { userSchema, UserSchema } from '../../openapi/spec/user-schema';
import { LoginSchema } from '../../openapi/spec/login-schema';
import { serializeDates } from '../../types/serialize-dates';
import { getStandardResponses } from '../../openapi';
export class SimplePasswordProvider extends Controller {
private logger: Logger;
@ -40,10 +41,14 @@ export class SimplePasswordProvider extends Controller {
middleware: [
openApiService.validPath({
tags: ['Auth'],
summary: 'Log in',
description:
'Logs in the user and creates an active session',
operationId: 'login',
requestBody: createRequestSchema('loginSchema'),
responses: {
200: createResponseSchema('userSchema'),
...getStandardResponses(401),
},
}),
],

View File

@ -295,7 +295,12 @@ class UserService {
const idQuery = isEmail(usernameOrEmail)
? { email: usernameOrEmail }
: { username: usernameOrEmail };
const user = await this.store.getByQuery(idQuery);
let user;
try {
user = await this.store.getByQuery(idQuery);
} catch (error) {}
if (user) {
const passwordHash = await this.store.getPasswordHash(user.id);
const match = await bcrypt.compare(password, passwordHash);
@ -303,7 +308,7 @@ class UserService {
await this.store.successfullyLogin(user);
return user;
}
}
throw new PasswordMismatch(
`The combination of password and username you provided is invalid. If you have forgotten your password, visit ${this.baseUriPath}/forgotten-password or get in touch with your instance administrator.`,
);

View File

@ -1227,11 +1227,16 @@ The provider you choose for your addon dictates what properties the \`parameters
},
"changePasswordSchema": {
"additionalProperties": false,
"description": "Change password as long as the token is a valid token",
"properties": {
"password": {
"description": "The new password for the user",
"example": "correct horse battery staple",
"type": "string",
},
"token": {
"description": "A reset token used to validate that the user is allowed to change the password.",
"example": "$2a$15$QzeW/y5/MEppCWVEkoX5euejobYOLSd4We21LQjjKlWH9l2I3wCke",
"type": "string",
},
},
@ -2082,8 +2087,11 @@ The provider you choose for your addon dictates what properties the \`parameters
},
"emailSchema": {
"additionalProperties": false,
"description": "Represents the email of a user. Used to send email communication (reset password, welcome mail etc)",
"properties": {
"email": {
"description": "The email address",
"example": "test@example.com",
"type": "string",
},
},
@ -3503,11 +3511,16 @@ The provider you choose for your addon dictates what properties the \`parameters
},
"loginSchema": {
"additionalProperties": false,
"description": "A username/password login request",
"properties": {
"password": {
"description": "The password of the user trying to log in",
"example": "hunter2",
"type": "string",
},
"username": {
"description": "The username trying to log in",
"example": "user",
"type": "string",
},
},
@ -4829,17 +4842,27 @@ Stats are divided into current and previous **windows**.
},
"roleSchema": {
"additionalProperties": false,
"description": "A role holds permissions to allow Unleash to decide what actions a role holder is allowed to perform",
"properties": {
"description": {
"description": "A more detailed description of the role and what use it's intended for",
"example": "Users with the editor role have access to most features in Unleash but can not manage users and roles in the global scope. Editors will be added as project owners when creating projects and get superuser rights within the context of these projects. Users with the editor role will also get access to most permissions on the default project by default.",
"type": "string",
},
"id": {
"type": "number",
"description": "The role id",
"example": 9,
"minimum": 0,
"type": "integer",
},
"name": {
"description": "The name of the role",
"example": "Editor",
"type": "string",
},
"type": {
"description": "A role can either be a global role (applies to all projects) or a project role",
"example": "global",
"type": "string",
},
},
@ -5395,24 +5418,35 @@ Stats are divided into current and previous **windows**.
},
"tokenUserSchema": {
"additionalProperties": false,
"description": "A user identified by a token",
"properties": {
"createdBy": {
"description": "A username or email identifying which user created this token",
"example": "admin@example.com",
"nullable": true,
"type": "string",
},
"email": {
"description": "The email of the user",
"example": "test@example.com",
"type": "string",
},
"id": {
"type": "number",
"description": "The user id",
"example": 7,
"type": "integer",
},
"name": {
"description": "The name of the user",
"example": "Test McTest",
"type": "string",
},
"role": {
"$ref": "#/components/schemas/roleSchema",
},
"token": {
"description": "A token uniquely identifying a user",
"example": "user:xyzrandomstring",
"type": "string",
},
},
@ -5769,47 +5803,78 @@ Stats are divided into current and previous **windows**.
},
"userSchema": {
"additionalProperties": false,
"description": "An Unleash user",
"properties": {
"accountType": {
"description": "A user is either an actual User or a Service Account",
"example": "User",
"type": "string",
},
"createdAt": {
"description": "The user was created at this time",
"example": "2023-06-30T11:41:00.123Z",
"format": "date-time",
"type": "string",
},
"email": {
"description": "Email of the user",
"example": "user@example.com",
"type": "string",
},
"emailSent": {
"description": "Is the welcome email sent to the user or not",
"example": false,
"type": "boolean",
},
"id": {
"type": "number",
"description": "The user id",
"example": 123,
"minimum": 0,
"type": "integer",
},
"imageUrl": {
"description": "URL used for the userprofile image",
"example": "https://example.com/242x200.png",
"type": "string",
},
"inviteLink": {
"description": "If the user is actively inviting other users, this is the link that can be shared with other users",
"example": "http://localhost:4242/invite-link/some-secret",
"type": "string",
},
"isAPI": {
"deprecated": true,
"description": "(Deprecated): Used internally to know which operations the user should be allowed to perform",
"example": true,
"type": "boolean",
},
"loginAttempts": {
"type": "number",
"description": "How many unsuccessful attempts at logging in has the user made",
"example": 3,
"minimum": 0,
"type": "integer",
},
"name": {
"description": "Name of the user",
"example": "User",
"type": "string",
},
"rootRole": {
"type": "number",
"description": "Which [root role](https://docs.getunleash.io/reference/rbac#standard-roles) this user is assigned",
"example": 1,
"minimum": 0,
"type": "integer",
},
"seenAt": {
"description": "The last time this user logged in",
"example": "2023-06-30T11:42:00.345Z",
"format": "date-time",
"nullable": true,
"type": "string",
},
"username": {
"description": "A unique username for the user",
"example": "hunter",
"type": "string",
},
},
@ -5865,8 +5930,11 @@ Stats are divided into current and previous **windows**.
},
"validatePasswordSchema": {
"additionalProperties": false,
"description": "Used to validate passwords obeying [Unleash password guidelines](https://docs.getunleash.io/reference/deploy/securing-unleash#password-requirements)",
"properties": {
"password": {
"description": "The password to validate",
"example": "hunter2",
"type": "string",
},
},
@ -14793,6 +14861,7 @@ true,false,"[{""range"":""allTime"",""count"":15},{""range"":""30d"",""count"":9
},
"/auth/reset/password": {
"post": {
"description": "Allows users with a valid reset token to reset their password without remembering their old password",
"operationId": "changePassword",
"requestBody": {
"content": {
@ -14809,7 +14878,89 @@ true,false,"[{""range"":""allTime"",""count"":15},{""range"":""30d"",""count"":9
"200": {
"description": "This response has no body.",
},
"401": {
"content": {
"application/json": {
"schema": {
"properties": {
"id": {
"description": "The ID of the error instance",
"example": "9c40958a-daac-400e-98fb-3bb438567008",
"type": "string",
},
"message": {
"description": "A description of what went wrong.",
"example": "You must log in to use Unleash. Your request had no authorization header, so we could not authorize you. Try logging in at /auth/simple/login.",
"type": "string",
},
"name": {
"description": "The name of the error kind",
"example": "AuthenticationRequired",
"type": "string",
},
},
"type": "object",
},
},
},
"description": "Authorization information is missing or invalid. Provide a valid API token as the \`authorization\` header, e.g. \`authorization:*.*.my-admin-token\`.",
},
"403": {
"content": {
"application/json": {
"schema": {
"properties": {
"id": {
"description": "The ID of the error instance",
"example": "9c40958a-daac-400e-98fb-3bb438567008",
"type": "string",
},
"message": {
"description": "A description of what went wrong.",
"example": "You need the "UPDATE_ADDON" permission to perform this action in the "development" environment.",
"type": "string",
},
"name": {
"description": "The name of the error kind",
"example": "NoAccessError",
"type": "string",
},
},
"type": "object",
},
},
},
"description": "User credentials are valid but does not have enough privileges to execute this operation",
},
"415": {
"content": {
"application/json": {
"schema": {
"properties": {
"id": {
"description": "The ID of the error instance",
"example": "9c40958a-daac-400e-98fb-3bb438567008",
"type": "string",
},
"message": {
"description": "A description of what went wrong.",
"example": "We do not accept the content-type you provided (application/xml). Try using one of the content-types we do accept instead (application/json) and make sure the body is in the corresponding format.",
"type": "string",
},
"name": {
"description": "The name of the error kind",
"example": "ContentTypeerror",
"type": "string",
},
},
"type": "object",
},
},
},
"description": "The operation does not support request payloads of the provided type. Please ensure that you're using one of the listed payload types and that you have specified the right content type in the "content-type" header.",
},
},
"summary": "Changes a user password",
"tags": [
"Auth",
],
@ -14817,6 +14968,7 @@ true,false,"[{""range"":""allTime"",""count"":15},{""range"":""30d"",""count"":9
},
"/auth/reset/password-email": {
"post": {
"description": "Requests a password reset email for the user. This email can be used to reset the password for a user that has forgotten their password",
"operationId": "sendResetPasswordEmail",
"requestBody": {
"content": {
@ -14833,7 +14985,89 @@ true,false,"[{""range"":""allTime"",""count"":15},{""range"":""30d"",""count"":9
"200": {
"description": "This response has no body.",
},
"401": {
"content": {
"application/json": {
"schema": {
"properties": {
"id": {
"description": "The ID of the error instance",
"example": "9c40958a-daac-400e-98fb-3bb438567008",
"type": "string",
},
"message": {
"description": "A description of what went wrong.",
"example": "You must log in to use Unleash. Your request had no authorization header, so we could not authorize you. Try logging in at /auth/simple/login.",
"type": "string",
},
"name": {
"description": "The name of the error kind",
"example": "AuthenticationRequired",
"type": "string",
},
},
"type": "object",
},
},
},
"description": "Authorization information is missing or invalid. Provide a valid API token as the \`authorization\` header, e.g. \`authorization:*.*.my-admin-token\`.",
},
"404": {
"content": {
"application/json": {
"schema": {
"properties": {
"id": {
"description": "The ID of the error instance",
"example": "9c40958a-daac-400e-98fb-3bb438567008",
"type": "string",
},
"message": {
"description": "A description of what went wrong.",
"example": "Could not find the addon with ID "12345".",
"type": "string",
},
"name": {
"description": "The name of the error kind",
"example": "NotFoundError",
"type": "string",
},
},
"type": "object",
},
},
},
"description": "The requested resource was not found.",
},
"415": {
"content": {
"application/json": {
"schema": {
"properties": {
"id": {
"description": "The ID of the error instance",
"example": "9c40958a-daac-400e-98fb-3bb438567008",
"type": "string",
},
"message": {
"description": "A description of what went wrong.",
"example": "We do not accept the content-type you provided (application/xml). Try using one of the content-types we do accept instead (application/json) and make sure the body is in the corresponding format.",
"type": "string",
},
"name": {
"description": "The name of the error kind",
"example": "ContentTypeerror",
"type": "string",
},
},
"type": "object",
},
},
},
"description": "The operation does not support request payloads of the provided type. Please ensure that you're using one of the listed payload types and that you have specified the right content type in the "content-type" header.",
},
},
"summary": "Reset password",
"tags": [
"Auth",
],
@ -14841,6 +15075,7 @@ true,false,"[{""range"":""allTime"",""count"":15},{""range"":""30d"",""count"":9
},
"/auth/reset/validate": {
"get": {
"description": "If the token is valid returns the user that owns the token",
"operationId": "validateToken",
"responses": {
"200": {
@ -14853,7 +15088,62 @@ true,false,"[{""range"":""allTime"",""count"":15},{""range"":""30d"",""count"":9
},
"description": "tokenUserSchema",
},
"401": {
"content": {
"application/json": {
"schema": {
"properties": {
"id": {
"description": "The ID of the error instance",
"example": "9c40958a-daac-400e-98fb-3bb438567008",
"type": "string",
},
"message": {
"description": "A description of what went wrong.",
"example": "You must log in to use Unleash. Your request had no authorization header, so we could not authorize you. Try logging in at /auth/simple/login.",
"type": "string",
},
"name": {
"description": "The name of the error kind",
"example": "AuthenticationRequired",
"type": "string",
},
},
"type": "object",
},
},
},
"description": "Authorization information is missing or invalid. Provide a valid API token as the \`authorization\` header, e.g. \`authorization:*.*.my-admin-token\`.",
},
"415": {
"content": {
"application/json": {
"schema": {
"properties": {
"id": {
"description": "The ID of the error instance",
"example": "9c40958a-daac-400e-98fb-3bb438567008",
"type": "string",
},
"message": {
"description": "A description of what went wrong.",
"example": "We do not accept the content-type you provided (application/xml). Try using one of the content-types we do accept instead (application/json) and make sure the body is in the corresponding format.",
"type": "string",
},
"name": {
"description": "The name of the error kind",
"example": "ContentTypeerror",
"type": "string",
},
},
"type": "object",
},
},
},
"description": "The operation does not support request payloads of the provided type. Please ensure that you're using one of the listed payload types and that you have specified the right content type in the "content-type" header.",
},
},
"summary": "Validates a token",
"tags": [
"Auth",
],
@ -14861,6 +15151,7 @@ true,false,"[{""range"":""allTime"",""count"":15},{""range"":""30d"",""count"":9
},
"/auth/reset/validate-password": {
"post": {
"description": "Verifies that the password adheres to the [Unleash password guidelines](https://docs.getunleash.io/reference/deploy/securing-unleash#password-requirements)",
"operationId": "validatePassword",
"requestBody": {
"content": {
@ -14877,7 +15168,62 @@ true,false,"[{""range"":""allTime"",""count"":15},{""range"":""30d"",""count"":9
"200": {
"description": "This response has no body.",
},
"400": {
"content": {
"application/json": {
"schema": {
"properties": {
"id": {
"description": "The ID of the error instance",
"example": "9c40958a-daac-400e-98fb-3bb438567008",
"type": "string",
},
"message": {
"description": "A description of what went wrong.",
"example": "The request payload you provided doesn't conform to the schema. The .parameters property should be object. You sent [].",
"type": "string",
},
"name": {
"description": "The name of the error kind",
"example": "ValidationError",
"type": "string",
},
},
"type": "object",
},
},
},
"description": "The request data does not match what we expect.",
},
"415": {
"content": {
"application/json": {
"schema": {
"properties": {
"id": {
"description": "The ID of the error instance",
"example": "9c40958a-daac-400e-98fb-3bb438567008",
"type": "string",
},
"message": {
"description": "A description of what went wrong.",
"example": "We do not accept the content-type you provided (application/xml). Try using one of the content-types we do accept instead (application/json) and make sure the body is in the corresponding format.",
"type": "string",
},
"name": {
"description": "The name of the error kind",
"example": "ContentTypeerror",
"type": "string",
},
},
"type": "object",
},
},
},
"description": "The operation does not support request payloads of the provided type. Please ensure that you're using one of the listed payload types and that you have specified the right content type in the "content-type" header.",
},
},
"summary": "Validates password",
"tags": [
"Auth",
],
@ -14885,6 +15231,7 @@ true,false,"[{""range"":""allTime"",""count"":15},{""range"":""30d"",""count"":9
},
"/auth/simple/login": {
"post": {
"description": "Logs in the user and creates an active session",
"operationId": "login",
"requestBody": {
"content": {
@ -14908,7 +15255,35 @@ true,false,"[{""range"":""allTime"",""count"":15},{""range"":""30d"",""count"":9
},
"description": "userSchema",
},
"401": {
"content": {
"application/json": {
"schema": {
"properties": {
"id": {
"description": "The ID of the error instance",
"example": "9c40958a-daac-400e-98fb-3bb438567008",
"type": "string",
},
"message": {
"description": "A description of what went wrong.",
"example": "You must log in to use Unleash. Your request had no authorization header, so we could not authorize you. Try logging in at /auth/simple/login.",
"type": "string",
},
"name": {
"description": "The name of the error kind",
"example": "AuthenticationRequired",
"type": "string",
},
},
"type": "object",
},
},
},
"description": "Authorization information is missing or invalid. Provide a valid API token as the \`authorization\` header, e.g. \`authorization:*.*.my-admin-token\`.",
},
},
"summary": "Log in",
"tags": [
"Auth",
],

View File

@ -16,6 +16,7 @@ import { addDays, minutesToMilliseconds } from 'date-fns';
import { GroupService } from '../../../lib/services/group-service';
import { randomId } from '../../../lib/util/random-id';
import { BadDataError } from '../../../lib/error';
import PasswordMismatch from '../../../lib/error/password-mismatch';
let db;
let stores;
@ -114,7 +115,11 @@ test('should not be able to login with deleted user', async () => {
await expect(
userService.loginUser('deleted_user', 'unleash4all'),
).rejects.toThrow(new NotFoundError(`No user found`));
).rejects.toThrow(
new PasswordMismatch(
`The combination of password and username you provided is invalid. If you have forgotten your password, visit /forgotten-password or get in touch with your instance administrator.`,
),
);
});
test('should not login user if simple auth is disabled', async () => {