mirror of
https://github.com/NginxProxyManager/nginx-proxy-manager.git
synced 2025-04-20 19:47:46 +03:00
CI stack for Authentik with ldap
This commit is contained in:
parent
a277a5d167
commit
6e820a36ac
9
Jenkinsfile
vendored
9
Jenkinsfile
vendored
@ -188,6 +188,11 @@ pipeline {
|
|||||||
sh 'docker logs $(docker-compose ps --all -q pdns) > debug/postgres/docker_pdns.log 2>&1'
|
sh 'docker logs $(docker-compose ps --all -q pdns) > debug/postgres/docker_pdns.log 2>&1'
|
||||||
sh 'docker logs $(docker-compose ps --all -q pdns-db) > debug/postgres/docker_pdns-db.log 2>&1'
|
sh 'docker logs $(docker-compose ps --all -q pdns-db) > debug/postgres/docker_pdns-db.log 2>&1'
|
||||||
sh 'docker logs $(docker-compose ps --all -q dnsrouter) > debug/postgres/docker_dnsrouter.log 2>&1'
|
sh 'docker logs $(docker-compose ps --all -q dnsrouter) > debug/postgres/docker_dnsrouter.log 2>&1'
|
||||||
|
sh 'docker logs $(docker-compose ps --all -q db-postgres) > debug/postgres/docker_db.log 2>&1'
|
||||||
|
sh 'docker logs $(docker-compose ps --all -q authentik) > debug/postgres/docker_authentik.log 2>&1'
|
||||||
|
sh 'docker logs $(docker-compose ps --all -q authentik-redis) > debug/postgres/docker_authentik-redis.log 2>&1'
|
||||||
|
sh 'docker logs $(docker-compose ps --all -q authentik-ldap) > debug/postgres/docker_authentik-ldap.log 2>&1'
|
||||||
|
|
||||||
junit 'test/results/junit/*'
|
junit 'test/results/junit/*'
|
||||||
sh 'docker-compose down --remove-orphans --volumes -t 30 || true'
|
sh 'docker-compose down --remove-orphans --volumes -t 30 || true'
|
||||||
}
|
}
|
||||||
@ -248,16 +253,16 @@ pipeline {
|
|||||||
printResult()
|
printResult()
|
||||||
}
|
}
|
||||||
failure {
|
failure {
|
||||||
|
archiveArtifacts(artifacts: 'debug/**/*', allowEmptyArchive: true)
|
||||||
dir(path: 'test') {
|
dir(path: 'test') {
|
||||||
archiveArtifacts allowEmptyArchive: true, artifacts: 'results/**/*', excludes: '**/*.xml'
|
archiveArtifacts allowEmptyArchive: true, artifacts: 'results/**/*', excludes: '**/*.xml'
|
||||||
}
|
}
|
||||||
archiveArtifacts(artifacts: 'debug/*', allowEmptyArchive: true)
|
|
||||||
}
|
}
|
||||||
unstable {
|
unstable {
|
||||||
|
archiveArtifacts(artifacts: 'debug/**/*', allowEmptyArchive: true)
|
||||||
dir(path: 'test') {
|
dir(path: 'test') {
|
||||||
archiveArtifacts allowEmptyArchive: true, artifacts: 'results/**/*', excludes: '**/*.xml'
|
archiveArtifacts allowEmptyArchive: true, artifacts: 'results/**/*', excludes: '**/*.xml'
|
||||||
}
|
}
|
||||||
archiveArtifacts(artifacts: 'debug/*', allowEmptyArchive: true)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,4 +18,4 @@ threshold:
|
|||||||
# package: 30
|
# package: 30
|
||||||
# (optional; default 0)
|
# (optional; default 0)
|
||||||
# The minimum total coverage project should have
|
# The minimum total coverage project should have
|
||||||
total: 34
|
total: 33
|
||||||
|
@ -24,7 +24,7 @@
|
|||||||
},
|
},
|
||||||
"type": {
|
"type": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"pattern": "^password$"
|
"pattern": "^(local|ldap|oidc)$"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -53,7 +53,7 @@
|
|||||||
},
|
},
|
||||||
"type": {
|
"type": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"pattern": "^password$"
|
"pattern": "^(local|ldap|oidc)$"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -125,14 +125,12 @@ INSERT INTO `user` (
|
|||||||
`created_at`,
|
`created_at`,
|
||||||
`updated_at`,
|
`updated_at`,
|
||||||
`name`,
|
`name`,
|
||||||
`nickname`,
|
|
||||||
`email`,
|
`email`,
|
||||||
`is_system`
|
`is_system`
|
||||||
) VALUES (
|
) VALUES (
|
||||||
ROUND(UNIX_TIMESTAMP(CURTIME(4)) * 1000),
|
ROUND(UNIX_TIMESTAMP(CURTIME(4)) * 1000),
|
||||||
ROUND(UNIX_TIMESTAMP(CURTIME(4)) * 1000),
|
ROUND(UNIX_TIMESTAMP(CURTIME(4)) * 1000),
|
||||||
"System",
|
"System",
|
||||||
"System",
|
|
||||||
"system@localhost",
|
"system@localhost",
|
||||||
TRUE
|
TRUE
|
||||||
);
|
);
|
||||||
|
@ -125,14 +125,12 @@ INSERT INTO "user" (
|
|||||||
"created_at",
|
"created_at",
|
||||||
"updated_at",
|
"updated_at",
|
||||||
"name",
|
"name",
|
||||||
"nickname",
|
|
||||||
"email",
|
"email",
|
||||||
"is_system"
|
"is_system"
|
||||||
) VALUES (
|
) VALUES (
|
||||||
EXTRACT(EPOCH FROM TIMESTAMP '2011-05-17 10:40:28.876944') * 1000,
|
EXTRACT(EPOCH FROM TIMESTAMP '2011-05-17 10:40:28.876944') * 1000,
|
||||||
EXTRACT(EPOCH FROM TIMESTAMP '2011-05-17 10:40:28.876944') * 1000,
|
EXTRACT(EPOCH FROM TIMESTAMP '2011-05-17 10:40:28.876944') * 1000,
|
||||||
'System',
|
'System',
|
||||||
'System',
|
|
||||||
'system@localhost',
|
'system@localhost',
|
||||||
TRUE
|
TRUE
|
||||||
);
|
);
|
||||||
|
@ -124,14 +124,12 @@ INSERT INTO `user` (
|
|||||||
created_at,
|
created_at,
|
||||||
updated_at,
|
updated_at,
|
||||||
name,
|
name,
|
||||||
nickname,
|
|
||||||
email,
|
email,
|
||||||
is_system
|
is_system
|
||||||
) VALUES (
|
) VALUES (
|
||||||
unixepoch() * 1000,
|
unixepoch() * 1000,
|
||||||
unixepoch() * 1000,
|
unixepoch() * 1000,
|
||||||
"System",
|
"System",
|
||||||
"System",
|
|
||||||
"system@localhost",
|
"system@localhost",
|
||||||
1
|
1
|
||||||
);
|
);
|
||||||
|
@ -97,13 +97,14 @@ func (s *testsuite) TestSave() {
|
|||||||
defer goleak.VerifyNone(s.T(), goleak.IgnoreAnyFunction("database/sql.(*DB).connectionOpener"))
|
defer goleak.VerifyNone(s.T(), goleak.IgnoreAnyFunction("database/sql.(*DB).connectionOpener"))
|
||||||
|
|
||||||
s.mock.ExpectBegin()
|
s.mock.ExpectBegin()
|
||||||
s.mock.ExpectQuery(regexp.QuoteMeta(`INSERT INTO "auth" ("created_at","updated_at","is_deleted","user_id","type","secret") VALUES ($1,$2,$3,$4,$5,$6) RETURNING "id"`)).
|
s.mock.ExpectQuery(regexp.QuoteMeta(`INSERT INTO "auth" ("created_at","updated_at","is_deleted","user_id","type","identity","secret") VALUES ($1,$2,$3,$4,$5,$6,$7) RETURNING "id"`)).
|
||||||
WithArgs(
|
WithArgs(
|
||||||
sqlmock.AnyArg(),
|
sqlmock.AnyArg(),
|
||||||
sqlmock.AnyArg(),
|
sqlmock.AnyArg(),
|
||||||
0,
|
0,
|
||||||
100,
|
100,
|
||||||
TypeLocal,
|
TypeLocal,
|
||||||
|
"",
|
||||||
"abc123",
|
"abc123",
|
||||||
).
|
).
|
||||||
WillReturnRows(sqlmock.NewRows([]string{"id"}).AddRow("11"))
|
WillReturnRows(sqlmock.NewRows([]string{"id"}).AddRow("11"))
|
||||||
|
@ -39,7 +39,6 @@ func (m *Model) LoadByID(id int) error {
|
|||||||
// Save will save this model to the DB
|
// Save will save this model to the DB
|
||||||
func (m *Model) Save() error {
|
func (m *Model) Save() error {
|
||||||
db := database.GetDB()
|
db := database.GetDB()
|
||||||
// todo: touch? not sure that save does this or not?
|
|
||||||
result := db.Save(m)
|
result := db.Save(m)
|
||||||
return result.Error
|
return result.Error
|
||||||
}
|
}
|
||||||
|
@ -84,7 +84,6 @@ func (s *testsuite) SetupTest() {
|
|||||||
).AddRow(
|
).AddRow(
|
||||||
11,
|
11,
|
||||||
"Jane Doe",
|
"Jane Doe",
|
||||||
"Jane",
|
|
||||||
"jane@example.com",
|
"jane@example.com",
|
||||||
true,
|
true,
|
||||||
false,
|
false,
|
||||||
@ -183,7 +182,6 @@ func (s *testsuite) TestSave() {
|
|||||||
sqlmock.AnyArg(),
|
sqlmock.AnyArg(),
|
||||||
0,
|
0,
|
||||||
"John Doe",
|
"John Doe",
|
||||||
"Jonny",
|
|
||||||
"sarah@example.com",
|
"sarah@example.com",
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
|
8
docker/ci.env
Normal file
8
docker/ci.env
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
AUTHENTIK_SECRET_KEY=gl8woZe8L6IIX8SC0c5Ocsj0xPkX5uJo5DVZCFl+L/QGbzuplfutYuua2ODNLEiDD3aFd9H2ylJmrke0
|
||||||
|
AUTHENTIK_REDIS__HOST=authentik-redis
|
||||||
|
AUTHENTIK_POSTGRESQL__HOST=db-postgres
|
||||||
|
AUTHENTIK_POSTGRESQL__USER=authentik
|
||||||
|
AUTHENTIK_POSTGRESQL__NAME=authentik
|
||||||
|
AUTHENTIK_POSTGRESQL__PASSWORD=07EKS5NLI6Tpv68tbdvrxfvj
|
||||||
|
AUTHENTIK_BOOTSTRAP_PASSWORD=admin
|
||||||
|
AUTHENTIK_BOOTSTRAP_EMAIL=admin@example.com
|
BIN
docker/ci/postgres/authentik.sql.gz
Normal file
BIN
docker/ci/postgres/authentik.sql.gz
Normal file
Binary file not shown.
@ -12,15 +12,63 @@ services:
|
|||||||
NPM_DB_SSLMODE: 'disable'
|
NPM_DB_SSLMODE: 'disable'
|
||||||
depends_on:
|
depends_on:
|
||||||
- db-postgres
|
- db-postgres
|
||||||
|
- authentik
|
||||||
|
- authentik-worker
|
||||||
|
- authentik-ldap
|
||||||
|
|
||||||
db-postgres:
|
db-postgres:
|
||||||
image: postgres:15
|
image: postgres:latest
|
||||||
environment:
|
environment:
|
||||||
POSTGRES_USER: 'npm'
|
POSTGRES_USER: 'npm'
|
||||||
POSTGRES_PASSWORD: 'npmpass'
|
POSTGRES_PASSWORD: 'npmpass'
|
||||||
POSTGRES_DB: 'npm'
|
POSTGRES_DB: 'npm'
|
||||||
volumes:
|
volumes:
|
||||||
- psql_vol:/var/lib/postgresql/data
|
- psql_vol:/var/lib/postgresql/data
|
||||||
|
- ./ci/postgres:/docker-entrypoint-initdb.d
|
||||||
|
|
||||||
|
authentik-redis:
|
||||||
|
image: 'redis:alpine'
|
||||||
|
command: --save 60 1 --loglevel warning
|
||||||
|
restart: unless-stopped
|
||||||
|
healthcheck:
|
||||||
|
test: ['CMD-SHELL', 'redis-cli ping | grep PONG']
|
||||||
|
start_period: 20s
|
||||||
|
interval: 30s
|
||||||
|
retries: 5
|
||||||
|
timeout: 3s
|
||||||
|
volumes:
|
||||||
|
- redis_vol:/data
|
||||||
|
|
||||||
|
authentik:
|
||||||
|
image: ghcr.io/goauthentik/server:2024.8.3
|
||||||
|
restart: unless-stopped
|
||||||
|
command: server
|
||||||
|
env_file:
|
||||||
|
- ci.env
|
||||||
|
depends_on:
|
||||||
|
- authentik-redis
|
||||||
|
- db-postgres
|
||||||
|
|
||||||
|
authentik-worker:
|
||||||
|
image: ghcr.io/goauthentik/server:2024.8.3
|
||||||
|
restart: unless-stopped
|
||||||
|
command: worker
|
||||||
|
env_file:
|
||||||
|
- ci.env
|
||||||
|
depends_on:
|
||||||
|
- authentik-redis
|
||||||
|
- db-postgres
|
||||||
|
|
||||||
|
authentik-ldap:
|
||||||
|
image: ghcr.io/goauthentik/ldap
|
||||||
|
environment:
|
||||||
|
AUTHENTIK_HOST: 'http://authentik:9000'
|
||||||
|
AUTHENTIK_INSECURE: 'true'
|
||||||
|
AUTHENTIK_TOKEN: '1N7z2r5PZrNBauuyDZSnlhU4gPSih7bkooIgqbvhzBbrA1MGYyDGZmBasJqU'
|
||||||
|
restart: unless-stopped
|
||||||
|
depends_on:
|
||||||
|
- authentik
|
||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
psql_vol:
|
psql_vol:
|
||||||
|
redis_vol:
|
||||||
|
@ -25,7 +25,6 @@ curl --request POST \
|
|||||||
--header 'Content-Type: application/json' \
|
--header 'Content-Type: application/json' \
|
||||||
--data '{
|
--data '{
|
||||||
"name": "Bobby Tables",
|
"name": "Bobby Tables",
|
||||||
"nickname": "Bobby",
|
|
||||||
"email": "you@example.com",
|
"email": "you@example.com",
|
||||||
"roles": ["admin"],
|
"roles": ["admin"],
|
||||||
"is_disabled": false,
|
"is_disabled": false,
|
||||||
|
@ -8,7 +8,6 @@ export interface AuthOptions {
|
|||||||
|
|
||||||
export interface NewUser {
|
export interface NewUser {
|
||||||
name: string;
|
name: string;
|
||||||
nickname: string;
|
|
||||||
email: string;
|
email: string;
|
||||||
isDisabled: boolean;
|
isDisabled: boolean;
|
||||||
auth: AuthOptions;
|
auth: AuthOptions;
|
||||||
|
@ -14,7 +14,6 @@ export interface UserAuth {
|
|||||||
export interface User {
|
export interface User {
|
||||||
id: number;
|
id: number;
|
||||||
name: string;
|
name: string;
|
||||||
nickname: string;
|
|
||||||
email: string;
|
email: string;
|
||||||
createdOn: number;
|
createdOn: number;
|
||||||
updatedOn: number;
|
updatedOn: number;
|
||||||
|
@ -185,6 +185,9 @@
|
|||||||
"error.email-already-exists": {
|
"error.email-already-exists": {
|
||||||
"defaultMessage": "Es existiert bereits ein Benutzer mit dieser E-Mail-Adresse"
|
"defaultMessage": "Es existiert bereits ein Benutzer mit dieser E-Mail-Adresse"
|
||||||
},
|
},
|
||||||
|
"error.invalid-auth-type": {
|
||||||
|
"defaultMessage": "Invalid authentication type"
|
||||||
|
},
|
||||||
"error.invalid-login-credentials": {
|
"error.invalid-login-credentials": {
|
||||||
"defaultMessage": "Ungültige Login-Details"
|
"defaultMessage": "Ungültige Login-Details"
|
||||||
},
|
},
|
||||||
@ -440,9 +443,6 @@
|
|||||||
"user.name": {
|
"user.name": {
|
||||||
"defaultMessage": "Name"
|
"defaultMessage": "Name"
|
||||||
},
|
},
|
||||||
"user.nickname": {
|
|
||||||
"defaultMessage": "Benutzername"
|
|
||||||
},
|
|
||||||
"user.password": {
|
"user.password": {
|
||||||
"defaultMessage": "Passwort"
|
"defaultMessage": "Passwort"
|
||||||
},
|
},
|
||||||
|
@ -461,6 +461,9 @@
|
|||||||
"error.email-already-exists": {
|
"error.email-already-exists": {
|
||||||
"defaultMessage": "A user already exists with this email address"
|
"defaultMessage": "A user already exists with this email address"
|
||||||
},
|
},
|
||||||
|
"error.invalid-auth-type": {
|
||||||
|
"defaultMessage": "Invalid authentication type"
|
||||||
|
},
|
||||||
"error.invalid-login-credentials": {
|
"error.invalid-login-credentials": {
|
||||||
"defaultMessage": "Invalid login credentials"
|
"defaultMessage": "Invalid login credentials"
|
||||||
},
|
},
|
||||||
@ -722,9 +725,6 @@
|
|||||||
"user.name": {
|
"user.name": {
|
||||||
"defaultMessage": "Name"
|
"defaultMessage": "Name"
|
||||||
},
|
},
|
||||||
"user.nickname": {
|
|
||||||
"defaultMessage": "Nickname"
|
|
||||||
},
|
|
||||||
"user.password": {
|
"user.password": {
|
||||||
"defaultMessage": "Password"
|
"defaultMessage": "Password"
|
||||||
},
|
},
|
||||||
|
@ -185,6 +185,9 @@
|
|||||||
"error.email-already-exists": {
|
"error.email-already-exists": {
|
||||||
"defaultMessage": "کاربری از قبل با این آدرس ایمیل وجود دارد"
|
"defaultMessage": "کاربری از قبل با این آدرس ایمیل وجود دارد"
|
||||||
},
|
},
|
||||||
|
"error.invalid-auth-type": {
|
||||||
|
"defaultMessage": "Invalid authentication type"
|
||||||
|
},
|
||||||
"error.invalid-login-credentials": {
|
"error.invalid-login-credentials": {
|
||||||
"defaultMessage": "اعتبار ورود نامعتبر است"
|
"defaultMessage": "اعتبار ورود نامعتبر است"
|
||||||
},
|
},
|
||||||
@ -443,9 +446,6 @@
|
|||||||
"user.name": {
|
"user.name": {
|
||||||
"defaultMessage": "نام"
|
"defaultMessage": "نام"
|
||||||
},
|
},
|
||||||
"user.nickname": {
|
|
||||||
"defaultMessage": "کنیه"
|
|
||||||
},
|
|
||||||
"user.password": {
|
"user.password": {
|
||||||
"defaultMessage": "کلمه عبور"
|
"defaultMessage": "کلمه عبور"
|
||||||
},
|
},
|
||||||
|
@ -5,19 +5,19 @@ import {
|
|||||||
FormLabel,
|
FormLabel,
|
||||||
Input,
|
Input,
|
||||||
Modal,
|
Modal,
|
||||||
ModalOverlay,
|
|
||||||
ModalContent,
|
|
||||||
ModalHeader,
|
|
||||||
ModalCloseButton,
|
|
||||||
ModalBody,
|
ModalBody,
|
||||||
|
ModalCloseButton,
|
||||||
|
ModalContent,
|
||||||
ModalFooter,
|
ModalFooter,
|
||||||
|
ModalHeader,
|
||||||
|
ModalOverlay,
|
||||||
Stack,
|
Stack,
|
||||||
useToast,
|
useToast,
|
||||||
} from "@chakra-ui/react";
|
} from "@chakra-ui/react";
|
||||||
import { Formik, Form, Field } from "formik";
|
import { Field, Form, Formik } from "formik";
|
||||||
|
|
||||||
import { PrettyButton } from "src/components";
|
import { PrettyButton } from "src/components";
|
||||||
import { useUser, useSetUser } from "src/hooks";
|
import { useSetUser, useUser } from "src/hooks";
|
||||||
import { intl } from "src/locale";
|
import { intl } from "src/locale";
|
||||||
import { validateEmail, validateString } from "src/modules/Validations";
|
import { validateEmail, validateString } from "src/modules/Validations";
|
||||||
|
|
||||||
@ -59,7 +59,6 @@ function ProfileModal({ isOpen, onClose }: ProfileModalProps) {
|
|||||||
<Formik
|
<Formik
|
||||||
initialValues={{
|
initialValues={{
|
||||||
name: user.data?.name,
|
name: user.data?.name,
|
||||||
nickname: user.data?.nickname,
|
|
||||||
email: user.data?.email,
|
email: user.data?.email,
|
||||||
}}
|
}}
|
||||||
onSubmit={onSubmit}>
|
onSubmit={onSubmit}>
|
||||||
@ -71,7 +70,7 @@ function ProfileModal({ isOpen, onClose }: ProfileModalProps) {
|
|||||||
<ModalCloseButton />
|
<ModalCloseButton />
|
||||||
<ModalBody>
|
<ModalBody>
|
||||||
<Stack spacing={4}>
|
<Stack spacing={4}>
|
||||||
<Field name="name" validate={validateString(2, 100)}>
|
<Field name="name" validate={validateString(2, 50)}>
|
||||||
{({ field, form }: any) => (
|
{({ field, form }: any) => (
|
||||||
<FormControl
|
<FormControl
|
||||||
isRequired
|
isRequired
|
||||||
@ -91,30 +90,6 @@ function ProfileModal({ isOpen, onClose }: ProfileModalProps) {
|
|||||||
</FormControl>
|
</FormControl>
|
||||||
)}
|
)}
|
||||||
</Field>
|
</Field>
|
||||||
<Field name="nickname" validate={validateString(2, 100)}>
|
|
||||||
{({ field, form }: any) => (
|
|
||||||
<FormControl
|
|
||||||
isRequired
|
|
||||||
isInvalid={
|
|
||||||
form.errors.nickname && form.touched.nickname
|
|
||||||
}>
|
|
||||||
<FormLabel htmlFor="nickname">
|
|
||||||
{intl.formatMessage({ id: "user.nickname" })}
|
|
||||||
</FormLabel>
|
|
||||||
<Input
|
|
||||||
{...field}
|
|
||||||
id="nickname"
|
|
||||||
defaultValue={values.nickname}
|
|
||||||
placeholder={intl.formatMessage({
|
|
||||||
id: "user.nickname",
|
|
||||||
})}
|
|
||||||
/>
|
|
||||||
<FormErrorMessage>
|
|
||||||
{form.errors.nickname}
|
|
||||||
</FormErrorMessage>
|
|
||||||
</FormControl>
|
|
||||||
)}
|
|
||||||
</Field>
|
|
||||||
<Field name="email" validate={validateEmail()}>
|
<Field name="email" validate={validateEmail()}>
|
||||||
{({ field, form }: any) => (
|
{({ field, form }: any) => (
|
||||||
<FormControl
|
<FormControl
|
||||||
|
@ -35,7 +35,6 @@ import { validateEmail, validateString } from "src/modules/Validations";
|
|||||||
|
|
||||||
interface Payload {
|
interface Payload {
|
||||||
name: string;
|
name: string;
|
||||||
nickname: string;
|
|
||||||
email: string;
|
email: string;
|
||||||
password: string;
|
password: string;
|
||||||
}
|
}
|
||||||
@ -110,7 +109,6 @@ function UserCreateModal({ isOpen, onClose }: UserCreateModalProps) {
|
|||||||
initialValues={
|
initialValues={
|
||||||
{
|
{
|
||||||
name: "",
|
name: "",
|
||||||
nickname: "",
|
|
||||||
email: "",
|
email: "",
|
||||||
password: "",
|
password: "",
|
||||||
} as Payload
|
} as Payload
|
||||||
@ -131,7 +129,7 @@ function UserCreateModal({ isOpen, onClose }: UserCreateModalProps) {
|
|||||||
<TabPanels>
|
<TabPanels>
|
||||||
<TabPanel>
|
<TabPanel>
|
||||||
<Stack spacing={4}>
|
<Stack spacing={4}>
|
||||||
<Field name="name" validate={validateString(2, 100)}>
|
<Field name="name" validate={validateString(2, 50)}>
|
||||||
{({ field, form }: any) => (
|
{({ field, form }: any) => (
|
||||||
<FormControl
|
<FormControl
|
||||||
isRequired
|
isRequired
|
||||||
@ -152,31 +150,6 @@ function UserCreateModal({ isOpen, onClose }: UserCreateModalProps) {
|
|||||||
</FormControl>
|
</FormControl>
|
||||||
)}
|
)}
|
||||||
</Field>
|
</Field>
|
||||||
<Field
|
|
||||||
name="nickname"
|
|
||||||
validate={validateString(2, 100)}>
|
|
||||||
{({ field, form }: any) => (
|
|
||||||
<FormControl
|
|
||||||
isRequired
|
|
||||||
isInvalid={
|
|
||||||
form.errors.nickname && form.touched.nickname
|
|
||||||
}>
|
|
||||||
<FormLabel htmlFor="nickname">
|
|
||||||
{intl.formatMessage({ id: "user.nickname" })}
|
|
||||||
</FormLabel>
|
|
||||||
<Input
|
|
||||||
{...field}
|
|
||||||
id="nickname"
|
|
||||||
placeholder={intl.formatMessage({
|
|
||||||
id: "user.nickname",
|
|
||||||
})}
|
|
||||||
/>
|
|
||||||
<FormErrorMessage>
|
|
||||||
{form.errors.nickname}
|
|
||||||
</FormErrorMessage>
|
|
||||||
</FormControl>
|
|
||||||
)}
|
|
||||||
</Field>
|
|
||||||
<Field name="email" validate={validateEmail()}>
|
<Field name="email" validate={validateEmail()}>
|
||||||
{({ field, form }: any) => (
|
{({ field, form }: any) => (
|
||||||
<FormControl
|
<FormControl
|
||||||
|
@ -8,28 +8,28 @@ import {
|
|||||||
FormLabel,
|
FormLabel,
|
||||||
Input,
|
Input,
|
||||||
Modal,
|
Modal,
|
||||||
ModalOverlay,
|
|
||||||
ModalContent,
|
|
||||||
ModalHeader,
|
|
||||||
ModalCloseButton,
|
|
||||||
ModalBody,
|
ModalBody,
|
||||||
|
ModalCloseButton,
|
||||||
|
ModalContent,
|
||||||
ModalFooter,
|
ModalFooter,
|
||||||
|
ModalHeader,
|
||||||
|
ModalOverlay,
|
||||||
Stack,
|
Stack,
|
||||||
Tab,
|
Tab,
|
||||||
Tabs,
|
|
||||||
TabList,
|
TabList,
|
||||||
TabPanel,
|
TabPanel,
|
||||||
TabPanels,
|
TabPanels,
|
||||||
|
Tabs,
|
||||||
useToast,
|
useToast,
|
||||||
} from "@chakra-ui/react";
|
} from "@chakra-ui/react";
|
||||||
import { Formik, Form, Field } from "formik";
|
import { Field, Form, Formik } from "formik";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
AdminPermissionSelector,
|
AdminPermissionSelector,
|
||||||
PermissionSelector,
|
PermissionSelector,
|
||||||
PrettyButton,
|
PrettyButton,
|
||||||
} from "src/components";
|
} from "src/components";
|
||||||
import { useUser, useSetUser } from "src/hooks";
|
import { useSetUser, useUser } from "src/hooks";
|
||||||
import { intl } from "src/locale";
|
import { intl } from "src/locale";
|
||||||
import { validateEmail, validateString } from "src/modules/Validations";
|
import { validateEmail, validateString } from "src/modules/Validations";
|
||||||
|
|
||||||
@ -106,7 +106,6 @@ function UserEditModal({ userId, isOpen, onClose }: UserEditModalProps) {
|
|||||||
initialValues={
|
initialValues={
|
||||||
{
|
{
|
||||||
name: data?.name,
|
name: data?.name,
|
||||||
nickname: data?.nickname,
|
|
||||||
email: data?.email,
|
email: data?.email,
|
||||||
isDisabled: data?.isDisabled,
|
isDisabled: data?.isDisabled,
|
||||||
} as any
|
} as any
|
||||||
@ -129,7 +128,7 @@ function UserEditModal({ userId, isOpen, onClose }: UserEditModalProps) {
|
|||||||
<TabPanels>
|
<TabPanels>
|
||||||
<TabPanel>
|
<TabPanel>
|
||||||
<Stack spacing={4}>
|
<Stack spacing={4}>
|
||||||
<Field name="name" validate={validateString(2, 100)}>
|
<Field name="name" validate={validateString(2, 50)}>
|
||||||
{({ field, form }: any) => (
|
{({ field, form }: any) => (
|
||||||
<FormControl
|
<FormControl
|
||||||
isRequired
|
isRequired
|
||||||
@ -152,31 +151,6 @@ function UserEditModal({ userId, isOpen, onClose }: UserEditModalProps) {
|
|||||||
</FormControl>
|
</FormControl>
|
||||||
)}
|
)}
|
||||||
</Field>
|
</Field>
|
||||||
<Field
|
|
||||||
name="nickname"
|
|
||||||
validate={validateString(2, 100)}>
|
|
||||||
{({ field, form }: any) => (
|
|
||||||
<FormControl
|
|
||||||
isRequired
|
|
||||||
isInvalid={
|
|
||||||
form.errors.nickname && form.touched.nickname
|
|
||||||
}>
|
|
||||||
<FormLabel htmlFor="nickname">
|
|
||||||
{intl.formatMessage({ id: "user.nickname" })}
|
|
||||||
</FormLabel>
|
|
||||||
<Input
|
|
||||||
{...field}
|
|
||||||
id="nickname"
|
|
||||||
placeholder={intl.formatMessage({
|
|
||||||
id: "user.nickname",
|
|
||||||
})}
|
|
||||||
/>
|
|
||||||
<FormErrorMessage>
|
|
||||||
{form.errors.nickname}
|
|
||||||
</FormErrorMessage>
|
|
||||||
</FormControl>
|
|
||||||
)}
|
|
||||||
</Field>
|
|
||||||
<Field name="email" validate={validateEmail()}>
|
<Field name="email" validate={validateEmail()}>
|
||||||
{({ field, form }: any) => (
|
{({ field, form }: any) => (
|
||||||
<FormControl
|
<FormControl
|
||||||
|
@ -1,10 +1,9 @@
|
|||||||
import { useEffect, useMemo, useState } from "react";
|
import { useEffect, useMemo, useState } from "react";
|
||||||
|
|
||||||
import { FiDownload, FiEdit, FiRefreshCw, FiTrash2 } from "react-icons/fi";
|
import { FiDownload, FiEdit, FiRefreshCw, FiTrash2 } from "react-icons/fi";
|
||||||
import { useSortBy, useFilters, useTable, usePagination } from "react-table";
|
import { useFilters, usePagination, useSortBy, useTable } from "react-table";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
tableEvents,
|
|
||||||
ActionsFormatter,
|
ActionsFormatter,
|
||||||
CertificateStatusFormatter,
|
CertificateStatusFormatter,
|
||||||
CertificateTypeFormatter,
|
CertificateTypeFormatter,
|
||||||
@ -12,6 +11,7 @@ import {
|
|||||||
GravatarFormatter,
|
GravatarFormatter,
|
||||||
IDFormatter,
|
IDFormatter,
|
||||||
MonospaceFormatter,
|
MonospaceFormatter,
|
||||||
|
tableEvents,
|
||||||
TableFilter,
|
TableFilter,
|
||||||
TableLayout,
|
TableLayout,
|
||||||
TablePagination,
|
TablePagination,
|
||||||
@ -123,7 +123,7 @@ function Table({
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
return [columns, data];
|
return [columns, data];
|
||||||
}, [data, onRenewal]);
|
}, [data, onRenewal, onDelete]);
|
||||||
|
|
||||||
const tableInstance = useTable(
|
const tableInstance = useTable(
|
||||||
{
|
{
|
||||||
|
@ -25,7 +25,6 @@ import { validateEmail, validateString } from "src/modules/Validations";
|
|||||||
|
|
||||||
interface Payload {
|
interface Payload {
|
||||||
name: string;
|
name: string;
|
||||||
nickname: string;
|
|
||||||
email: string;
|
email: string;
|
||||||
password: string;
|
password: string;
|
||||||
}
|
}
|
||||||
@ -122,7 +121,6 @@ function Setup() {
|
|||||||
initialValues={
|
initialValues={
|
||||||
{
|
{
|
||||||
name: "",
|
name: "",
|
||||||
nickname: "",
|
|
||||||
email: "",
|
email: "",
|
||||||
password: "",
|
password: "",
|
||||||
} as Payload
|
} as Payload
|
||||||
@ -131,7 +129,7 @@ function Setup() {
|
|||||||
{({ isSubmitting }) => (
|
{({ isSubmitting }) => (
|
||||||
<Form>
|
<Form>
|
||||||
<Stack spacing={4}>
|
<Stack spacing={4}>
|
||||||
<Field name="name" validate={validateString(2, 100)}>
|
<Field name="name" validate={validateString(2, 50)}>
|
||||||
{({ field, form }: any) => (
|
{({ field, form }: any) => (
|
||||||
<FormControl
|
<FormControl
|
||||||
isRequired
|
isRequired
|
||||||
@ -153,29 +151,6 @@ function Setup() {
|
|||||||
</FormControl>
|
</FormControl>
|
||||||
)}
|
)}
|
||||||
</Field>
|
</Field>
|
||||||
<Field name="nickname" validate={validateString(2, 100)}>
|
|
||||||
{({ field, form }: any) => (
|
|
||||||
<FormControl
|
|
||||||
isRequired
|
|
||||||
isInvalid={
|
|
||||||
form.errors.nickname && form.touched.nickname
|
|
||||||
}>
|
|
||||||
<FormLabel htmlFor="nickname">
|
|
||||||
{intl.formatMessage({ id: "user.nickname" })}
|
|
||||||
</FormLabel>
|
|
||||||
<Input
|
|
||||||
{...field}
|
|
||||||
id="nickname"
|
|
||||||
placeholder={intl.formatMessage({
|
|
||||||
id: "user.nickname",
|
|
||||||
})}
|
|
||||||
/>
|
|
||||||
<FormErrorMessage>
|
|
||||||
{form.errors.nickname}
|
|
||||||
</FormErrorMessage>
|
|
||||||
</FormControl>
|
|
||||||
)}
|
|
||||||
</Field>
|
|
||||||
<Field name="email" validate={validateEmail()}>
|
<Field name="email" validate={validateEmail()}>
|
||||||
{({ field, form }: any) => (
|
{({ field, form }: any) => (
|
||||||
<FormControl
|
<FormControl
|
||||||
|
@ -71,6 +71,7 @@ printf "nameserver %s\noptions ndots:0" "${DNSROUTER_IP}" > "${LOCAL_RESOLVE}"
|
|||||||
docker-compose up -d --remove-orphans stepca
|
docker-compose up -d --remove-orphans stepca
|
||||||
docker-compose pull db-mysql || true # ok to fail
|
docker-compose pull db-mysql || true # ok to fail
|
||||||
docker-compose pull db-postgres || true # ok to fail
|
docker-compose pull db-postgres || true # ok to fail
|
||||||
|
docker-compose pull authentik authentik-redis authentik-ldap || true # ok to fail
|
||||||
docker-compose up -d --remove-orphans --pull=never fullstack
|
docker-compose up -d --remove-orphans --pull=never fullstack
|
||||||
|
|
||||||
# wait for main container to be healthy
|
# wait for main container to be healthy
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/// <reference types="Cypress" />
|
/// <reference types="cypress" />
|
||||||
|
|
||||||
describe('Certificates endpoints', () => {
|
describe('Certificates endpoints', () => {
|
||||||
let token;
|
let token;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/// <reference types="Cypress" />
|
/// <reference types="cypress" />
|
||||||
|
|
||||||
describe('Full Certificate Provisions', () => {
|
describe('Full Certificate Provisions', () => {
|
||||||
let token;
|
let token;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/// <reference types="Cypress" />
|
/// <reference types="cypress" />
|
||||||
|
|
||||||
describe('Basic API checks', () => {
|
describe('Basic API checks', () => {
|
||||||
it('Should return a valid health payload', function() {
|
it('Should return a valid health payload', function() {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/// <reference types="Cypress" />
|
/// <reference types="cypress" />
|
||||||
|
|
||||||
// Settings are stored lowercase in the backend
|
// Settings are stored lowercase in the backend
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/// <reference types="Cypress" />
|
/// <reference types="cypress" />
|
||||||
|
|
||||||
describe('Setup Phase', () => {
|
describe('Setup Phase', () => {
|
||||||
|
|
||||||
@ -8,15 +8,15 @@ describe('Setup Phase', () => {
|
|||||||
|
|
||||||
it('Should NOT be able to get a token', function() {
|
it('Should NOT be able to get a token', function() {
|
||||||
cy.task('backendApiPost', {
|
cy.task('backendApiPost', {
|
||||||
path: '/api/tokens',
|
path: '/api/auth',
|
||||||
data: {
|
data: {
|
||||||
type: 'password',
|
type: 'local',
|
||||||
identity: 'cypress@example.com',
|
identity: 'cypress@example.com',
|
||||||
secret: 'changeme'
|
secret: 'changeme'
|
||||||
},
|
},
|
||||||
returnOnError: true
|
returnOnError: true
|
||||||
}).then((data) => {
|
}).then((data) => {
|
||||||
cy.validateSwaggerSchema('post', 403, '/tokens', data);
|
cy.validateSwaggerSchema('post', 403, '/auth', data);
|
||||||
expect(data.error).to.have.property('code', 403);
|
expect(data.error).to.have.property('code', 403);
|
||||||
expect(data.error).to.have.property('message', 'Not available during setup phase');
|
expect(data.error).to.have.property('message', 'Not available during setup phase');
|
||||||
});
|
});
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/// <reference types="Cypress" />
|
/// <reference types="cypress" />
|
||||||
|
|
||||||
describe('Swagger Schema Checks', () => {
|
describe('Swagger Schema Checks', () => {
|
||||||
it('Should be valid with swagger-validator', function() {
|
it('Should be valid with swagger-validator', function() {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/// <reference types="Cypress" />
|
/// <reference types="cypress" />
|
||||||
|
|
||||||
describe('Upstream endpoints', () => {
|
describe('Upstream endpoints', () => {
|
||||||
let token;
|
let token;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/// <reference types="Cypress" />
|
/// <reference types="cypress" />
|
||||||
|
|
||||||
describe('Users endpoints', () => {
|
describe('Users endpoints', () => {
|
||||||
let token;
|
let token;
|
||||||
@ -82,11 +82,10 @@ describe('Users endpoints', () => {
|
|||||||
path: '/api/users',
|
path: '/api/users',
|
||||||
data: {
|
data: {
|
||||||
name: 'Example user 1',
|
name: 'Example user 1',
|
||||||
nickname: 'User1',
|
|
||||||
email: uniqueEmail,
|
email: uniqueEmail,
|
||||||
is_disabled: false,
|
is_disabled: false,
|
||||||
auth: {
|
auth: {
|
||||||
type: 'password',
|
type: 'local',
|
||||||
secret: 'changeme'
|
secret: 'changeme'
|
||||||
},
|
},
|
||||||
capabilities: [
|
capabilities: [
|
||||||
@ -108,11 +107,10 @@ describe('Users endpoints', () => {
|
|||||||
returnOnError: true,
|
returnOnError: true,
|
||||||
data: {
|
data: {
|
||||||
name: 'Example user 2',
|
name: 'Example user 2',
|
||||||
nickname: 'User2',
|
|
||||||
email: uniqueEmail,
|
email: uniqueEmail,
|
||||||
is_disabled: false,
|
is_disabled: false,
|
||||||
auth: {
|
auth: {
|
||||||
type: 'password',
|
type: 'local',
|
||||||
secret: 'changeme'
|
secret: 'changeme'
|
||||||
},
|
},
|
||||||
capabilities: [
|
capabilities: [
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/// <reference types="Cypress" />
|
/// <reference types="cypress" />
|
||||||
|
|
||||||
describe('UI Setup and Login', () => {
|
describe('UI Setup and Login', () => {
|
||||||
|
|
||||||
@ -10,7 +10,6 @@ describe('UI Setup and Login', () => {
|
|||||||
it('Should be able to setup a new user', function() {
|
it('Should be able to setup a new user', function() {
|
||||||
cy.visit('/');
|
cy.visit('/');
|
||||||
cy.get('input[name="name"]').type('Cypress McGee');
|
cy.get('input[name="name"]').type('Cypress McGee');
|
||||||
cy.get('input[name="nickname"]').type('Cypress');
|
|
||||||
cy.get('input[name="email"]').type('cypress@example.com');
|
cy.get('input[name="email"]').type('cypress@example.com');
|
||||||
cy.get('input[name="password"]').type('changeme');
|
cy.get('input[name="password"]').type('changeme');
|
||||||
cy.get('form button:last').click();
|
cy.get('form button:last').click();
|
||||||
|
@ -66,7 +66,7 @@ Cypress.Commands.add('getToken', (defaultUser, defaultAuth) => {
|
|||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
let auth = {
|
let auth = {
|
||||||
type: 'password',
|
type: 'local',
|
||||||
identity: 'cypress@example.com',
|
identity: 'cypress@example.com',
|
||||||
secret: 'changeme',
|
secret: 'changeme',
|
||||||
};
|
};
|
||||||
@ -78,7 +78,7 @@ Cypress.Commands.add('getToken', (defaultUser, defaultAuth) => {
|
|||||||
cy.log('Setup = true');
|
cy.log('Setup = true');
|
||||||
// login with existing user
|
// login with existing user
|
||||||
cy.task('backendApiPost', {
|
cy.task('backendApiPost', {
|
||||||
path: '/api/tokens',
|
path: '/api/auth',
|
||||||
data: auth,
|
data: auth,
|
||||||
}).then((res) => {
|
}).then((res) => {
|
||||||
cy.wrap(res.result.token);
|
cy.wrap(res.result.token);
|
||||||
@ -90,11 +90,10 @@ Cypress.Commands.add('getToken', (defaultUser, defaultAuth) => {
|
|||||||
Cypress.Commands.add('createInitialUser', (defaultUser) => {
|
Cypress.Commands.add('createInitialUser', (defaultUser) => {
|
||||||
let user = {
|
let user = {
|
||||||
name: 'Cypress McGee',
|
name: 'Cypress McGee',
|
||||||
nickname: 'Cypress',
|
|
||||||
email: 'cypress@example.com',
|
email: 'cypress@example.com',
|
||||||
is_disabled: false,
|
is_disabled: false,
|
||||||
auth: {
|
auth: {
|
||||||
type: 'password',
|
type: 'local',
|
||||||
secret: 'changeme'
|
secret: 'changeme'
|
||||||
},
|
},
|
||||||
capabilities: ['full-admin']
|
capabilities: ['full-admin']
|
||||||
|
Loading…
x
Reference in New Issue
Block a user