Compare commits
4 Commits
master
...
feat-oidc-
Author | SHA1 | Date |
---|---|---|
James Elliott | 33fdacb6e1 | |
James Elliott | f290fd90b1 | |
James Elliott | 2f9da2b7e0 | |
James Elliott | 5e5eead729 |
|
@ -7,4 +7,3 @@
|
||||||
!entrypoint.sh
|
!entrypoint.sh
|
||||||
!healthcheck.sh
|
!healthcheck.sh
|
||||||
!.healthcheck.env
|
!.healthcheck.env
|
||||||
!dist/public_html/
|
|
95
MyNotes.md
95
MyNotes.md
|
@ -1,95 +0,0 @@
|
||||||
# Ausführen
|
|
||||||
|
|
||||||
Um die Anwendung lokal auszuführen, können die folgenden Befehle verwendet werden.
|
|
||||||
|
|
||||||
```
|
|
||||||
export GOPATH=/tmp
|
|
||||||
source bootstrap.sh
|
|
||||||
authelia-scripts suites setup Standalone
|
|
||||||
```
|
|
||||||
|
|
||||||
Nun sollte der "Haupt-Enpunkt" unter `https://home.example.com:8080` und die API unter `https://authelia.example.com:9091` erreichbar sein. Achtung: es wird ein selbstsigniertes Zertifikat verwendet!
|
|
||||||
Mithilfe der Hot-Reload kann jetzt gecoded werden.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
Nach der Entwicklung kann die Testumgebung durch den folgenden Befehl wieder zurückgesetzt werden.
|
|
||||||
|
|
||||||
```
|
|
||||||
go run ./cmd/authelia-scripts/ suites teardown Standalone
|
|
||||||
```
|
|
||||||
|
|
||||||
## Benutzerdefinierte Zertifikate
|
|
||||||
|
|
||||||
Um ein benutzerdefiniertes Zertifikat für die Ausführung zu verwenden, muss die Datai `public.backend.crt` und `private.bakend.pem` unter [diesem](/internal/suites/common/pki/) Verzeichnis abgeändert werden.
|
|
||||||
Um die Gültigkeit zu testen, kann der folgendende Befehl ausgeführt werden.
|
|
||||||
|
|
||||||
```
|
|
||||||
curl https://auth.rpjosh.de:9091 --connect-to 'auth.rpjosh.de:9091:authelia.example.com:9091'
|
|
||||||
```
|
|
||||||
|
|
||||||
## Externe erreichbarkeit
|
|
||||||
|
|
||||||
Im aktuellen Zustand sind die Endpunkte nur unter den Docker internen IP-Adressen erreichbar. Daher muss noch ein NAT Regel angelegt werden.
|
|
||||||
|
|
||||||
```
|
|
||||||
ip=$(ping -c 1 authelia.example.com | gawk -F'[()]' '/PING/{print $2}')
|
|
||||||
sudo iptables -t nat -A PREROUTING -p tcp --dport 9091 -d 192.168.0.15 -j DNAT --to-destination 192.168.240.50:9091 -m comment --comment "Authelia-Test"
|
|
||||||
sudo iptables -t nat -A PREROUTING -p tcp --dport 9092 -d 192.168.0.15 -j DNAT --to-destination 192.168.240.50:9092 -m comment --comment "Authelia-Test"
|
|
||||||
sudo iptables -t nat -I OUTPUT -p tcp -o lo --dport 9091 -j DNAT --to-destination 192.168.240.50:9091
|
|
||||||
```
|
|
||||||
|
|
||||||
# Customizations
|
|
||||||
|
|
||||||
Für das Starten des *gRPC* Servers müssen die folgenden Abhängigkeiten installiert werden.
|
|
||||||
|
|
||||||
```
|
|
||||||
go get github.com/envoyproxy/go-control-plane
|
|
||||||
go get github.com/envoyproxy/go-control-plane/envoy/config/core/v3
|
|
||||||
go get github.com/gogo/googleapis/google/rpc
|
|
||||||
go get google.golang.org/grpc
|
|
||||||
```
|
|
||||||
|
|
||||||
## Konfiguration ändern
|
|
||||||
|
|
||||||
Wenn die Konfiguration geändert wurde, müssen die Keys zur Validierung wieder erneut gebaut werden.
|
|
||||||
|
|
||||||
```
|
|
||||||
go run ./cmd/authelia-gen code keys
|
|
||||||
```
|
|
||||||
|
|
||||||
## Mocks abgeändert
|
|
||||||
|
|
||||||
Wenn interfaces von den Mocks geändert werden, muss folgendes wieder ausgeführt werden:
|
|
||||||
|
|
||||||
```
|
|
||||||
export PATH=$PATH:$(go env GOPATH)/bin
|
|
||||||
go generate ./...
|
|
||||||
```
|
|
||||||
|
|
||||||
## Bauen
|
|
||||||
|
|
||||||
Um ein Docker Image für authelia zu bauen, müssen die folgenden Befehle ausgeführt werden.
|
|
||||||
|
|
||||||
```sh
|
|
||||||
# Dieser Befehle funktionieren aktuell nicht
|
|
||||||
authelia-scripts docker build
|
|
||||||
authelia-scripts build
|
|
||||||
|
|
||||||
# => Manuell bauen
|
|
||||||
export CC=musl-gcc
|
|
||||||
|
|
||||||
authelia-scripts build
|
|
||||||
cp -r dist/public_html internal/server/
|
|
||||||
go build -buildmode=pie -ldflags "-linkmode=external -s -w" -trimpath -buildmode=pie -o authelia ./cmd/authelia
|
|
||||||
mv authelia authelia-linux-amd64-musl
|
|
||||||
# Build docker image
|
|
||||||
docker build --tag git.rpjosh.de/rpjosh/authelia/authelia:4.38.0-dev .
|
|
||||||
docker push git.rpjosh.de/rpjosh/authelia/authelia:4.38.0-dev
|
|
||||||
# Cleanup
|
|
||||||
rm -rf internal/server/public_html/ ./authelia-linux-amd64-musl
|
|
||||||
```
|
|
||||||
|
|
||||||
# gRCP
|
|
||||||
|
|
||||||
Um einen gRCP Endpunkt nutzen zu können, brauch mein eine *.proto* Datei. Für Envoy sieht diese wie in [dieser Datei](/ext-auth.proto) folgendermaßen aus.
|
|
|
@ -62,10 +62,6 @@ server:
|
||||||
## This is disabled by default if either /app/.healthcheck.env or /app/healthcheck.sh do not exist.
|
## This is disabled by default if either /app/.healthcheck.env or /app/healthcheck.sh do not exist.
|
||||||
disable_healthcheck: false
|
disable_healthcheck: false
|
||||||
|
|
||||||
## If a request over the insecure http protocol is received from authelias gRPC endpoint (only for envoy),
|
|
||||||
## the request is by default redirected to the matching https URL (301)
|
|
||||||
disable_autho_https_redirect: false
|
|
||||||
|
|
||||||
## Authelia by default doesn't accept TLS communication on the server port. This section overrides this behaviour.
|
## Authelia by default doesn't accept TLS communication on the server port. This section overrides this behaviour.
|
||||||
tls:
|
tls:
|
||||||
## The path to the DER base64/PEM format private key.
|
## The path to the DER base64/PEM format private key.
|
||||||
|
@ -77,17 +73,6 @@ server:
|
||||||
## The list of certificates for client authentication.
|
## The list of certificates for client authentication.
|
||||||
client_certificates: []
|
client_certificates: []
|
||||||
|
|
||||||
## Enable the support for gRPC ext authentication for envoy. If TLS is enabled in the above section,
|
|
||||||
## the defined certificates will also be used for the gRPC endpoint
|
|
||||||
grpc:
|
|
||||||
address: 'tcp://:9092'
|
|
||||||
|
|
||||||
# Even if TLS is configured in the server setting (under server.tls), the grcp server won't use TLS
|
|
||||||
disableTLS: false
|
|
||||||
|
|
||||||
# By default the ban is issued for the user. With this options the IP instead of the user will be banned
|
|
||||||
use_ip_for_ban: true
|
|
||||||
|
|
||||||
## Server headers configuration/customization.
|
## Server headers configuration/customization.
|
||||||
headers:
|
headers:
|
||||||
|
|
||||||
|
|
|
@ -1,144 +0,0 @@
|
||||||
syntax = "proto3";
|
|
||||||
|
|
||||||
package envoy.service.auth.v3;
|
|
||||||
|
|
||||||
import "envoy/config/core/v3/base.proto";
|
|
||||||
import "envoy/service/auth/v3/attribute_context.proto";
|
|
||||||
import "envoy/type/v3/http_status.proto";
|
|
||||||
|
|
||||||
import "google/protobuf/struct.proto";
|
|
||||||
import "google/rpc/status.proto";
|
|
||||||
|
|
||||||
import "envoy/annotations/deprecation.proto";
|
|
||||||
import "udpa/annotations/status.proto";
|
|
||||||
import "udpa/annotations/versioning.proto";
|
|
||||||
|
|
||||||
option java_package = "io.envoyproxy.envoy.service.auth.v3";
|
|
||||||
option java_outer_classname = "ExternalAuthProto";
|
|
||||||
option java_multiple_files = true;
|
|
||||||
option go_package = "github.com/envoyproxy/go-control-plane/envoy/service/auth/v3;authv3";
|
|
||||||
option (udpa.annotations.file_status).package_version_status = ACTIVE;
|
|
||||||
|
|
||||||
// [#protodoc-title: Authorization service]
|
|
||||||
|
|
||||||
// The authorization service request messages used by external authorization :ref:`network filter
|
|
||||||
// <config_network_filters_ext_authz>` and :ref:`HTTP filter <config_http_filters_ext_authz>`.
|
|
||||||
|
|
||||||
// A generic interface for performing authorization check on incoming
|
|
||||||
// requests to a networked service.
|
|
||||||
service Authorization {
|
|
||||||
// Performs authorization check based on the attributes associated with the
|
|
||||||
// incoming request, and returns status `OK` or not `OK`.
|
|
||||||
rpc Check(CheckRequest) returns (CheckResponse) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
message CheckRequest {
|
|
||||||
option (udpa.annotations.versioning).previous_message_type = "envoy.service.auth.v2.CheckRequest";
|
|
||||||
|
|
||||||
// The request attributes.
|
|
||||||
AttributeContext attributes = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// HTTP attributes for a denied response.
|
|
||||||
message DeniedHttpResponse {
|
|
||||||
option (udpa.annotations.versioning).previous_message_type =
|
|
||||||
"envoy.service.auth.v2.DeniedHttpResponse";
|
|
||||||
|
|
||||||
// This field allows the authorization service to send an HTTP response status code to the
|
|
||||||
// downstream client. If not set, Envoy sends ``403 Forbidden`` HTTP status code by default.
|
|
||||||
type.v3.HttpStatus status = 1;
|
|
||||||
|
|
||||||
// This field allows the authorization service to send HTTP response headers
|
|
||||||
// to the downstream client. Note that the :ref:`append field in HeaderValueOption <envoy_v3_api_field_config.core.v3.HeaderValueOption.append>` defaults to
|
|
||||||
// false when used in this message.
|
|
||||||
repeated config.core.v3.HeaderValueOption headers = 2;
|
|
||||||
|
|
||||||
// This field allows the authorization service to send a response body data
|
|
||||||
// to the downstream client.
|
|
||||||
string body = 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
// HTTP attributes for an OK response.
|
|
||||||
// [#next-free-field: 9]
|
|
||||||
message OkHttpResponse {
|
|
||||||
option (udpa.annotations.versioning).previous_message_type =
|
|
||||||
"envoy.service.auth.v2.OkHttpResponse";
|
|
||||||
|
|
||||||
// HTTP entity headers in addition to the original request headers. This allows the authorization
|
|
||||||
// service to append, to add or to override headers from the original request before
|
|
||||||
// dispatching it to the upstream. Note that the :ref:`append field in HeaderValueOption <envoy_v3_api_field_config.core.v3.HeaderValueOption.append>` defaults to
|
|
||||||
// false when used in this message. By setting the ``append`` field to ``true``,
|
|
||||||
// the filter will append the correspondent header value to the matched request header.
|
|
||||||
// By leaving ``append`` as false, the filter will either add a new header, or override an existing
|
|
||||||
// one if there is a match.
|
|
||||||
repeated config.core.v3.HeaderValueOption headers = 2;
|
|
||||||
|
|
||||||
// HTTP entity headers to remove from the original request before dispatching
|
|
||||||
// it to the upstream. This allows the authorization service to act on auth
|
|
||||||
// related headers (like ``Authorization``), process them, and consume them.
|
|
||||||
// Under this model, the upstream will either receive the request (if it's
|
|
||||||
// authorized) or not receive it (if it's not), but will not see headers
|
|
||||||
// containing authorization credentials.
|
|
||||||
//
|
|
||||||
// Pseudo headers (such as ``:authority``, ``:method``, ``:path`` etc), as well as
|
|
||||||
// the header ``Host``, may not be removed as that would make the request
|
|
||||||
// malformed. If mentioned in ``headers_to_remove`` these special headers will
|
|
||||||
// be ignored.
|
|
||||||
//
|
|
||||||
// When using the HTTP service this must instead be set by the HTTP
|
|
||||||
// authorization service as a comma separated list like so:
|
|
||||||
// ``x-envoy-auth-headers-to-remove: one-auth-header, another-auth-header``.
|
|
||||||
repeated string headers_to_remove = 5;
|
|
||||||
|
|
||||||
// This field has been deprecated in favor of :ref:`CheckResponse.dynamic_metadata
|
|
||||||
// <envoy_v3_api_field_service.auth.v3.CheckResponse.dynamic_metadata>`. Until it is removed,
|
|
||||||
// setting this field overrides :ref:`CheckResponse.dynamic_metadata
|
|
||||||
// <envoy_v3_api_field_service.auth.v3.CheckResponse.dynamic_metadata>`.
|
|
||||||
google.protobuf.Struct dynamic_metadata = 3
|
|
||||||
[deprecated = true, (envoy.annotations.deprecated_at_minor_version) = "3.0"];
|
|
||||||
|
|
||||||
// This field allows the authorization service to send HTTP response headers
|
|
||||||
// to the downstream client on success. Note that the :ref:`append field in HeaderValueOption <envoy_v3_api_field_config.core.v3.HeaderValueOption.append>`
|
|
||||||
// defaults to false when used in this message.
|
|
||||||
repeated config.core.v3.HeaderValueOption response_headers_to_add = 6;
|
|
||||||
|
|
||||||
// This field allows the authorization service to set (and overwrite) query
|
|
||||||
// string parameters on the original request before it is sent upstream.
|
|
||||||
repeated config.core.v3.QueryParameter query_parameters_to_set = 7;
|
|
||||||
|
|
||||||
// This field allows the authorization service to specify which query parameters
|
|
||||||
// should be removed from the original request before it is sent upstream. Each
|
|
||||||
// element in this list is a case-sensitive query parameter name to be removed.
|
|
||||||
repeated string query_parameters_to_remove = 8;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Intended for gRPC and Network Authorization servers ``only``.
|
|
||||||
message CheckResponse {
|
|
||||||
option (udpa.annotations.versioning).previous_message_type =
|
|
||||||
"envoy.service.auth.v2.CheckResponse";
|
|
||||||
|
|
||||||
// Status ``OK`` allows the request. Any other status indicates the request should be denied, and
|
|
||||||
// for HTTP filter, if not overridden by :ref:`denied HTTP response status <envoy_v3_api_field_service.auth.v3.DeniedHttpResponse.status>`
|
|
||||||
// Envoy sends ``403 Forbidden`` HTTP status code by default.
|
|
||||||
google.rpc.Status status = 1;
|
|
||||||
|
|
||||||
// An message that contains HTTP response attributes. This message is
|
|
||||||
// used when the authorization service needs to send custom responses to the
|
|
||||||
// downstream client or, to modify/add request headers being dispatched to the upstream.
|
|
||||||
oneof http_response {
|
|
||||||
// Supplies http attributes for a denied response.
|
|
||||||
DeniedHttpResponse denied_response = 2;
|
|
||||||
|
|
||||||
// Supplies http attributes for an ok response.
|
|
||||||
OkHttpResponse ok_response = 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Optional response metadata that will be emitted as dynamic metadata to be consumed by the next
|
|
||||||
// filter. This metadata lives in a namespace specified by the canonical name of extension filter
|
|
||||||
// that requires it:
|
|
||||||
//
|
|
||||||
// - :ref:`envoy.filters.http.ext_authz <config_http_filters_ext_authz_dynamic_metadata>` for HTTP filter.
|
|
||||||
// - :ref:`envoy.filters.network.ext_authz <config_network_filters_ext_authz_dynamic_metadata>` for network filter.
|
|
||||||
google.protobuf.Struct dynamic_metadata = 4;
|
|
||||||
}
|
|
|
@ -45,7 +45,7 @@ services:
|
||||||
- TZ=Australia/Melbourne
|
- TZ=Australia/Melbourne
|
||||||
|
|
||||||
traefik:
|
traefik:
|
||||||
image: traefik:v2.10.3
|
image: traefik:v2.10.1
|
||||||
container_name: traefik
|
container_name: traefik
|
||||||
volumes:
|
volumes:
|
||||||
- ./traefik:/etc/traefik
|
- ./traefik:/etc/traefik
|
||||||
|
|
|
@ -32,7 +32,7 @@ services:
|
||||||
- TZ=Australia/Melbourne
|
- TZ=Australia/Melbourne
|
||||||
|
|
||||||
traefik:
|
traefik:
|
||||||
image: traefik:v2.10.3
|
image: traefik:v2.10.1
|
||||||
container_name: traefik
|
container_name: traefik
|
||||||
volumes:
|
volumes:
|
||||||
- ./traefik:/etc/traefik
|
- ./traefik:/etc/traefik
|
||||||
|
|
22
go.mod
22
go.mod
|
@ -33,7 +33,7 @@ require (
|
||||||
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826
|
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826
|
||||||
github.com/ory/fosite v0.44.0
|
github.com/ory/fosite v0.44.0
|
||||||
github.com/ory/herodot v0.10.2
|
github.com/ory/herodot v0.10.2
|
||||||
github.com/ory/x v0.0.563
|
github.com/ory/x v0.0.561
|
||||||
github.com/otiai10/copy v1.12.0
|
github.com/otiai10/copy v1.12.0
|
||||||
github.com/pkg/errors v0.9.1
|
github.com/pkg/errors v0.9.1
|
||||||
github.com/pquerna/otp v1.4.0
|
github.com/pquerna/otp v1.4.0
|
||||||
|
@ -43,7 +43,7 @@ require (
|
||||||
github.com/spf13/pflag v1.0.5
|
github.com/spf13/pflag v1.0.5
|
||||||
github.com/stretchr/testify v1.8.4
|
github.com/stretchr/testify v1.8.4
|
||||||
github.com/trustelem/zxcvbn v1.0.1
|
github.com/trustelem/zxcvbn v1.0.1
|
||||||
github.com/valyala/fasthttp v1.48.0
|
github.com/valyala/fasthttp v1.47.0
|
||||||
github.com/wneessen/go-mail v0.3.9
|
github.com/wneessen/go-mail v0.3.9
|
||||||
golang.org/x/net v0.11.0
|
golang.org/x/net v0.11.0
|
||||||
golang.org/x/sync v0.3.0
|
golang.org/x/sync v0.3.0
|
||||||
|
@ -59,7 +59,6 @@ require (
|
||||||
github.com/beorn7/perks v1.0.1 // indirect
|
github.com/beorn7/perks v1.0.1 // indirect
|
||||||
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc // indirect
|
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc // indirect
|
||||||
github.com/cespare/xxhash/v2 v2.2.0 // indirect
|
github.com/cespare/xxhash/v2 v2.2.0 // indirect
|
||||||
github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4 // indirect
|
|
||||||
github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
|
github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
|
||||||
github.com/cristalhq/jwt/v4 v4.0.2 // indirect
|
github.com/cristalhq/jwt/v4 v4.0.2 // indirect
|
||||||
github.com/dave/jennifer v1.6.0 // indirect
|
github.com/dave/jennifer v1.6.0 // indirect
|
||||||
|
@ -69,16 +68,12 @@ require (
|
||||||
github.com/dlclark/regexp2 v1.4.0 // indirect
|
github.com/dlclark/regexp2 v1.4.0 // indirect
|
||||||
github.com/dustin/go-humanize v1.0.0 // indirect
|
github.com/dustin/go-humanize v1.0.0 // indirect
|
||||||
github.com/ecordell/optgen v0.0.6 // indirect
|
github.com/ecordell/optgen v0.0.6 // indirect
|
||||||
github.com/envoyproxy/go-control-plane v0.11.1 // indirect
|
|
||||||
github.com/envoyproxy/protoc-gen-validate v1.0.1 // indirect
|
|
||||||
github.com/facebookgo/stack v0.0.0-20160209184415-751773369052 // indirect
|
github.com/facebookgo/stack v0.0.0-20160209184415-751773369052 // indirect
|
||||||
github.com/fxamacker/cbor/v2 v2.4.0 // indirect
|
github.com/fxamacker/cbor/v2 v2.4.0 // indirect
|
||||||
github.com/go-crypt/x v0.2.1 // indirect
|
github.com/go-crypt/x v0.2.1 // indirect
|
||||||
github.com/go-redis/redis/v8 v8.11.5 // indirect
|
github.com/go-redis/redis/v8 v8.11.5 // indirect
|
||||||
github.com/go-webauthn/revoke v0.1.9 // indirect
|
github.com/go-webauthn/revoke v0.1.9 // indirect
|
||||||
github.com/gogo/googleapis v1.4.1 // indirect
|
github.com/golang/glog v1.0.0 // indirect
|
||||||
github.com/gogo/protobuf v1.3.2 // indirect
|
|
||||||
github.com/golang/glog v1.1.0 // indirect
|
|
||||||
github.com/golang/protobuf v1.5.3 // indirect
|
github.com/golang/protobuf v1.5.3 // indirect
|
||||||
github.com/google/go-tpm v0.3.3 // indirect
|
github.com/google/go-tpm v0.3.3 // indirect
|
||||||
github.com/gorilla/websocket v1.5.0 // indirect
|
github.com/gorilla/websocket v1.5.0 // indirect
|
||||||
|
@ -102,7 +97,7 @@ require (
|
||||||
github.com/pelletier/go-toml/v2 v2.0.6 // indirect
|
github.com/pelletier/go-toml/v2 v2.0.6 // indirect
|
||||||
github.com/philhofer/fwd v1.1.2 // indirect
|
github.com/philhofer/fwd v1.1.2 // indirect
|
||||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||||
github.com/prometheus/client_model v0.4.0 // indirect
|
github.com/prometheus/client_model v0.3.0 // indirect
|
||||||
github.com/prometheus/common v0.42.0 // indirect
|
github.com/prometheus/common v0.42.0 // indirect
|
||||||
github.com/prometheus/procfs v0.10.1 // indirect
|
github.com/prometheus/procfs v0.10.1 // indirect
|
||||||
github.com/redis/go-redis/v9 v9.0.4 // indirect
|
github.com/redis/go-redis/v9 v9.0.4 // indirect
|
||||||
|
@ -124,13 +119,12 @@ require (
|
||||||
github.com/ysmood/leakless v0.8.0 // indirect
|
github.com/ysmood/leakless v0.8.0 // indirect
|
||||||
golang.org/x/crypto v0.10.0 // indirect
|
golang.org/x/crypto v0.10.0 // indirect
|
||||||
golang.org/x/mod v0.10.0 // indirect
|
golang.org/x/mod v0.10.0 // indirect
|
||||||
golang.org/x/oauth2 v0.7.0 // indirect
|
golang.org/x/oauth2 v0.5.0 // indirect
|
||||||
golang.org/x/sys v0.9.0 // indirect
|
golang.org/x/sys v0.9.0 // indirect
|
||||||
golang.org/x/tools v0.8.0 // indirect
|
golang.org/x/tools v0.7.0 // indirect
|
||||||
google.golang.org/appengine v1.6.7 // indirect
|
google.golang.org/appengine v1.6.7 // indirect
|
||||||
google.golang.org/genproto v0.0.0-20230526203410-71b5a4ffd15e // indirect
|
google.golang.org/genproto v0.0.0-20230403163135-c38d8f061ccd // indirect
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20230526203410-71b5a4ffd15e // indirect
|
google.golang.org/grpc v1.54.0 // indirect
|
||||||
google.golang.org/grpc v1.56.0 // indirect
|
|
||||||
google.golang.org/protobuf v1.30.0 // indirect
|
google.golang.org/protobuf v1.30.0 // indirect
|
||||||
gopkg.in/ini.v1 v1.67.0 // indirect
|
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||||
|
|
38
go.sum
38
go.sum
|
@ -72,8 +72,6 @@ github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDk
|
||||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||||
github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||||
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||||
github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4 h1:/inchEIKaYC1Akx+H+gqO04wryn5h75LSazbRlnya1k=
|
|
||||||
github.com/cncf/xds/go v0.0.0-20230607035331-e9ce68804cb4/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
|
||||||
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
|
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
|
||||||
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
||||||
github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
|
github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
|
||||||
|
@ -115,11 +113,7 @@ github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.m
|
||||||
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
||||||
github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po=
|
github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po=
|
||||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
|
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
|
||||||
github.com/envoyproxy/go-control-plane v0.11.1 h1:wSUXTlLfiAQRWs2F+p+EKOY9rUyis1MyGqJ2DIk5HpM=
|
|
||||||
github.com/envoyproxy/go-control-plane v0.11.1/go.mod h1:uhMcXKCQMEJHiAb0w+YGefQLaTEw+YhGluxZkrTmD0g=
|
|
||||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||||
github.com/envoyproxy/protoc-gen-validate v1.0.1 h1:kt9FtLiooDc0vbwTLhdg3dyNX1K9Qwa1EK9LcD4jVUQ=
|
|
||||||
github.com/envoyproxy/protoc-gen-validate v1.0.1/go.mod h1:0vj8bNkYbSTNS2PIyH87KZaeN4x9zpL9Qt8fQC7d+vs=
|
|
||||||
github.com/facebookgo/stack v0.0.0-20160209184415-751773369052 h1:JWuenKqqX8nojtoVVWjGfOF9635RETekkoH6Cc9SX0A=
|
github.com/facebookgo/stack v0.0.0-20160209184415-751773369052 h1:JWuenKqqX8nojtoVVWjGfOF9635RETekkoH6Cc9SX0A=
|
||||||
github.com/facebookgo/stack v0.0.0-20160209184415-751773369052/go.mod h1:UbMTZqLaRiH3MsBH8va0n7s1pQYcu3uTb8G4tygF4Zg=
|
github.com/facebookgo/stack v0.0.0-20160209184415-751773369052/go.mod h1:UbMTZqLaRiH3MsBH8va0n7s1pQYcu3uTb8G4tygF4Zg=
|
||||||
github.com/fasthttp/router v1.4.19 h1:RLE539IU/S4kfb4MP56zgP0TIBU9kEg0ID9GpWO0vqk=
|
github.com/fasthttp/router v1.4.19 h1:RLE539IU/S4kfb4MP56zgP0TIBU9kEg0ID9GpWO0vqk=
|
||||||
|
@ -160,19 +154,13 @@ github.com/go-webauthn/revoke v0.1.9 h1:gSJ1ckA9VaKA2GN4Ukp+kiGTk1/EXtaDb1YE8Rkn
|
||||||
github.com/go-webauthn/revoke v0.1.9/go.mod h1:j6WKPnv0HovtEs++paan9g3ar46gm1NarktkXBaPR+w=
|
github.com/go-webauthn/revoke v0.1.9/go.mod h1:j6WKPnv0HovtEs++paan9g3ar46gm1NarktkXBaPR+w=
|
||||||
github.com/go-webauthn/webauthn v0.5.0 h1:Tbmp37AGIhYbQmcy2hEffo3U3cgPClqvxJ7cLUnF7Rc=
|
github.com/go-webauthn/webauthn v0.5.0 h1:Tbmp37AGIhYbQmcy2hEffo3U3cgPClqvxJ7cLUnF7Rc=
|
||||||
github.com/go-webauthn/webauthn v0.5.0/go.mod h1:0CBq/jNfPS9l033j4AxMk8K8MluiMsde9uGNSPFLEVE=
|
github.com/go-webauthn/webauthn v0.5.0/go.mod h1:0CBq/jNfPS9l033j4AxMk8K8MluiMsde9uGNSPFLEVE=
|
||||||
github.com/gogo/googleapis v1.4.1 h1:1Yx4Myt7BxzvUr5ldGSbwYiZG6t9wGBZ+8/fX3Wvtq0=
|
|
||||||
github.com/gogo/googleapis v1.4.1/go.mod h1:2lpHqI5OcWCtVElxXnPt+s8oJvMpySlOyM6xDCrzib4=
|
|
||||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||||
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
|
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
|
||||||
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
|
||||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
|
||||||
github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg=
|
github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg=
|
||||||
github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
|
github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
|
||||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||||
github.com/golang/glog v1.0.0 h1:nfP3RFugxnNRyKgeWd4oI1nYvXpxrx8ck8ZrcizshdQ=
|
github.com/golang/glog v1.0.0 h1:nfP3RFugxnNRyKgeWd4oI1nYvXpxrx8ck8ZrcizshdQ=
|
||||||
github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4=
|
github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4=
|
||||||
github.com/golang/glog v1.1.0 h1:/d3pCKDPWNnvIWe0vVUpNP32qc8U3PDVxySP/y360qE=
|
|
||||||
github.com/golang/glog v1.1.0/go.mod h1:pfYeQZ3JWZoXTV5sFc986z3HTpwQs9At6P4ImfuP3NQ=
|
|
||||||
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||||
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||||
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||||
|
@ -279,7 +267,6 @@ github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1
|
||||||
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
|
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
|
||||||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||||
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
|
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
|
||||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
|
||||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||||
github.com/klauspost/compress v1.16.5 h1:IFV2oUNUzZaz+XyusxpLzpzS8Pt5rh0Z16For/djlyI=
|
github.com/klauspost/compress v1.16.5 h1:IFV2oUNUzZaz+XyusxpLzpzS8Pt5rh0Z16For/djlyI=
|
||||||
github.com/klauspost/compress v1.16.5/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
|
github.com/klauspost/compress v1.16.5/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
|
||||||
|
@ -344,8 +331,8 @@ github.com/ory/go-convenience v0.1.0 h1:zouLKfF2GoSGnJwGq+PE/nJAE6dj2Zj5QlTgmMTs
|
||||||
github.com/ory/go-convenience v0.1.0/go.mod h1:uEY/a60PL5c12nYz4V5cHY03IBmwIAEm8TWB0yn9KNs=
|
github.com/ory/go-convenience v0.1.0/go.mod h1:uEY/a60PL5c12nYz4V5cHY03IBmwIAEm8TWB0yn9KNs=
|
||||||
github.com/ory/herodot v0.10.2 h1:gGvNMHgAwWzdP/eo+roSiT5CGssygHSjDU7MSQNlJ4E=
|
github.com/ory/herodot v0.10.2 h1:gGvNMHgAwWzdP/eo+roSiT5CGssygHSjDU7MSQNlJ4E=
|
||||||
github.com/ory/herodot v0.10.2/go.mod h1:MMNmY6MG1uB6fnXYFaHoqdV23DTWctlPsmRCeq/2+wc=
|
github.com/ory/herodot v0.10.2/go.mod h1:MMNmY6MG1uB6fnXYFaHoqdV23DTWctlPsmRCeq/2+wc=
|
||||||
github.com/ory/x v0.0.563 h1:T77Bjt6ALMZmUJIsQ5UEkzDBCD+8vxfQlBCU1Y39uDk=
|
github.com/ory/x v0.0.561 h1:SvNDGd6OhvAFl4XiPnYJuLCtR6iLxZJcF1Vzlo1IFTM=
|
||||||
github.com/ory/x v0.0.563/go.mod h1:kup4ebSC4SzwU6KPZJ4G60UR3EEsHxJ0apQVflVw5yQ=
|
github.com/ory/x v0.0.561/go.mod h1:kup4ebSC4SzwU6KPZJ4G60UR3EEsHxJ0apQVflVw5yQ=
|
||||||
github.com/otiai10/copy v1.12.0 h1:cLMgSQnXBs1eehF0Wy/FAGsgDTDmAqFR7rQylBb1nDY=
|
github.com/otiai10/copy v1.12.0 h1:cLMgSQnXBs1eehF0Wy/FAGsgDTDmAqFR7rQylBb1nDY=
|
||||||
github.com/otiai10/copy v1.12.0/go.mod h1:rSaLseMUsZFFbsFGc7wCJnnkTAvdc5L6VWxPE4308Ww=
|
github.com/otiai10/copy v1.12.0/go.mod h1:rSaLseMUsZFFbsFGc7wCJnnkTAvdc5L6VWxPE4308Ww=
|
||||||
github.com/otiai10/mint v1.5.1 h1:XaPLeE+9vGbuyEHem1JNk3bYc7KKqyI/na0/mLd/Kks=
|
github.com/otiai10/mint v1.5.1 h1:XaPLeE+9vGbuyEHem1JNk3bYc7KKqyI/na0/mLd/Kks=
|
||||||
|
@ -376,8 +363,6 @@ github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:
|
||||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||||
github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4=
|
github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4=
|
||||||
github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w=
|
github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w=
|
||||||
github.com/prometheus/client_model v0.4.0 h1:5lQXD3cAg1OXBf4Wq03gTrXHeaV0TQvGfUooCfx1yqY=
|
|
||||||
github.com/prometheus/client_model v0.4.0/go.mod h1:oMQmHW1/JoDwqLtg57MGgP/Fb1CJEYF2imWWhWtMkYU=
|
|
||||||
github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
|
github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
|
||||||
github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||||
github.com/prometheus/common v0.42.0 h1:EKsfXEYo4JpWMHH5cg+KOUWeuJSov1Id8zGR8eeI1YM=
|
github.com/prometheus/common v0.42.0 h1:EKsfXEYo4JpWMHH5cg+KOUWeuJSov1Id8zGR8eeI1YM=
|
||||||
|
@ -451,8 +436,8 @@ github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGr
|
||||||
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
|
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
|
||||||
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
|
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
|
||||||
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
||||||
github.com/valyala/fasthttp v1.48.0 h1:oJWvHb9BIZToTQS3MuQ2R3bJZiNSa2KiNdeI8A+79Tc=
|
github.com/valyala/fasthttp v1.47.0 h1:y7moDoxYzMooFpT5aHgNgVOQDrS3qlkfiP9mDtGGK9c=
|
||||||
github.com/valyala/fasthttp v1.48.0/go.mod h1:k2zXd82h/7UZc3VOdJ2WaUqt1uZ/XpXAfE9i+HBC3lA=
|
github.com/valyala/fasthttp v1.47.0/go.mod h1:k2zXd82h/7UZc3VOdJ2WaUqt1uZ/XpXAfE9i+HBC3lA=
|
||||||
github.com/wneessen/go-mail v0.3.9 h1:Q4DbCk3htT5DtDWKeMgNXCiHc4bBY/vv/XQPT6XDXzc=
|
github.com/wneessen/go-mail v0.3.9 h1:Q4DbCk3htT5DtDWKeMgNXCiHc4bBY/vv/XQPT6XDXzc=
|
||||||
github.com/wneessen/go-mail v0.3.9/go.mod h1:zxOlafWCP/r6FEhAaRgH4IC1vg2YXxO0Nar9u0IScZ8=
|
github.com/wneessen/go-mail v0.3.9/go.mod h1:zxOlafWCP/r6FEhAaRgH4IC1vg2YXxO0Nar9u0IScZ8=
|
||||||
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
|
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
|
||||||
|
@ -594,10 +579,6 @@ golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ
|
||||||
golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||||
golang.org/x/oauth2 v0.5.0 h1:HuArIo48skDwlrvM3sEdHXElYslAMsf3KwRkkW4MC4s=
|
golang.org/x/oauth2 v0.5.0 h1:HuArIo48skDwlrvM3sEdHXElYslAMsf3KwRkkW4MC4s=
|
||||||
golang.org/x/oauth2 v0.5.0/go.mod h1:9/XBHVqLaWO3/BRHs5jbpYCnOZVjj5V0ndyaAM7KB4I=
|
golang.org/x/oauth2 v0.5.0/go.mod h1:9/XBHVqLaWO3/BRHs5jbpYCnOZVjj5V0ndyaAM7KB4I=
|
||||||
golang.org/x/oauth2 v0.6.0 h1:Lh8GPgSKBfWSwFvtuWOfeI3aAAnbXTSutYxJiOJFgIw=
|
|
||||||
golang.org/x/oauth2 v0.6.0/go.mod h1:ycmewcwgD4Rpr3eZJLSB4Kyyljb3qDh40vJ8STE5HKw=
|
|
||||||
golang.org/x/oauth2 v0.7.0 h1:qe6s0zUXlPX80/dITx3440hWZ7GwMwgDDyrSGTPJG/g=
|
|
||||||
golang.org/x/oauth2 v0.7.0/go.mod h1:hPLQkd9LyjfXTiRohC/41GhcFqxisoUQ99sCUOHO9x4=
|
|
||||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
@ -726,7 +707,6 @@ golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roY
|
||||||
golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||||
golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||||
golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||||
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
|
||||||
golang.org/x/tools v0.0.0-20200717024301-6ddee64345a6/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
golang.org/x/tools v0.0.0-20200717024301-6ddee64345a6/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||||
golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||||
golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||||
|
@ -736,7 +716,6 @@ golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4f
|
||||||
golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||||
golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||||
golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
|
||||||
golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||||
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
|
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
|
||||||
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||||
|
@ -745,7 +724,6 @@ golang.org/x/tools v0.4.0/go.mod h1:UE5sM2OK9E/d67R0ANs2xJizIymRP5gJU295PvKXxjQ=
|
||||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||||
golang.org/x/tools v0.7.0 h1:W4OVu8VVOaIO0yzWMNdepAulS7YfoS3Zabrm8DOXXU4=
|
golang.org/x/tools v0.7.0 h1:W4OVu8VVOaIO0yzWMNdepAulS7YfoS3Zabrm8DOXXU4=
|
||||||
golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s=
|
golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s=
|
||||||
golang.org/x/tools v0.8.0/go.mod h1:JxBZ99ISMI5ViVkT1tr6tdNmXeTrcpVSD3vZ1RsRdN4=
|
|
||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
@ -815,10 +793,6 @@ google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6D
|
||||||
google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||||
google.golang.org/genproto v0.0.0-20230403163135-c38d8f061ccd h1:sLpv7bNL1AsX3fdnWh9WVh7ejIzXdOc1RRHGeAmeStU=
|
google.golang.org/genproto v0.0.0-20230403163135-c38d8f061ccd h1:sLpv7bNL1AsX3fdnWh9WVh7ejIzXdOc1RRHGeAmeStU=
|
||||||
google.golang.org/genproto v0.0.0-20230403163135-c38d8f061ccd/go.mod h1:UUQDJDOlWu4KYeJZffbWgBkS1YFobzKbLVfK69pe0Ak=
|
google.golang.org/genproto v0.0.0-20230403163135-c38d8f061ccd/go.mod h1:UUQDJDOlWu4KYeJZffbWgBkS1YFobzKbLVfK69pe0Ak=
|
||||||
google.golang.org/genproto v0.0.0-20230526203410-71b5a4ffd15e h1:Ao9GzfUMPH3zjVfzXG5rlWlk+Q8MXWKwWpwVQE1MXfw=
|
|
||||||
google.golang.org/genproto v0.0.0-20230526203410-71b5a4ffd15e/go.mod h1:zqTuNwFlFRsw5zIts5VnzLQxSRqh+CGOTVMlYbY0Eyk=
|
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20230526203410-71b5a4ffd15e h1:NumxXLPfHSndr3wBBdeKiVHjGVFzi9RX2HwwQke94iY=
|
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20230526203410-71b5a4ffd15e/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA=
|
|
||||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||||
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
||||||
google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
||||||
|
@ -838,10 +812,6 @@ google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA5
|
||||||
google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
||||||
google.golang.org/grpc v1.54.0 h1:EhTqbhiYeixwWQtAEZAxmV9MGqcjEU2mFx52xCzNyag=
|
google.golang.org/grpc v1.54.0 h1:EhTqbhiYeixwWQtAEZAxmV9MGqcjEU2mFx52xCzNyag=
|
||||||
google.golang.org/grpc v1.54.0/go.mod h1:PUSEXI6iWghWaB6lXM4knEgpJNu2qUcKfDtNci3EC2g=
|
google.golang.org/grpc v1.54.0/go.mod h1:PUSEXI6iWghWaB6lXM4knEgpJNu2qUcKfDtNci3EC2g=
|
||||||
google.golang.org/grpc v1.55.0 h1:3Oj82/tFSCeUrRTg/5E/7d/W5A1tj6Ky1ABAuZuv5ag=
|
|
||||||
google.golang.org/grpc v1.55.0/go.mod h1:iYEXKGkEBhg1PjZQvoYEVPTDkHo1/bjTnfwTeGONTY8=
|
|
||||||
google.golang.org/grpc v1.56.0 h1:+y7Bs8rtMd07LeXmL3NxcTLn7mUkbKZqEpPhMNkwJEE=
|
|
||||||
google.golang.org/grpc v1.56.0/go.mod h1:I9bI3vqKfayGqPUAwGdOSu7kt6oIJLixfffKrpXqQ9s=
|
|
||||||
google.golang.org/grpc/examples v0.0.0-20210304020650-930c79186c99 h1:qA8rMbz1wQ4DOFfM2ouD29DG9aHWBm6ZOy9BGxiUMmY=
|
google.golang.org/grpc/examples v0.0.0-20210304020650-930c79186c99 h1:qA8rMbz1wQ4DOFfM2ouD29DG9aHWBm6ZOy9BGxiUMmY=
|
||||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||||
|
|
|
@ -208,6 +208,10 @@ func domainToPrefixSuffix(domain string) (prefix, suffix string) {
|
||||||
return parts[0], strings.Join(parts[1:], ".")
|
return parts[0], strings.Join(parts[1:], ".")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func NewSubjects(subjectRules [][]string) (subjects []AccessControlSubjects) {
|
||||||
|
return schemaSubjectsToACL(subjectRules)
|
||||||
|
}
|
||||||
|
|
||||||
// IsAuthLevelSufficient returns true if the current authenticationLevel is above the authorizationLevel.
|
// IsAuthLevelSufficient returns true if the current authenticationLevel is above the authorizationLevel.
|
||||||
func IsAuthLevelSufficient(authenticationLevel authentication.Level, authorizationLevel Level) bool {
|
func IsAuthLevelSufficient(authenticationLevel authentication.Level, authorizationLevel Level) bool {
|
||||||
switch authorizationLevel {
|
switch authorizationLevel {
|
||||||
|
|
|
@ -16,7 +16,6 @@ import (
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
"github.com/valyala/fasthttp"
|
"github.com/valyala/fasthttp"
|
||||||
"golang.org/x/sync/errgroup"
|
"golang.org/x/sync/errgroup"
|
||||||
"google.golang.org/grpc"
|
|
||||||
|
|
||||||
"github.com/authelia/authelia/v4/internal/authentication"
|
"github.com/authelia/authelia/v4/internal/authentication"
|
||||||
"github.com/authelia/authelia/v4/internal/server"
|
"github.com/authelia/authelia/v4/internal/server"
|
||||||
|
@ -34,17 +33,6 @@ func NewServerService(name string, server *fasthttp.Server, listener net.Listene
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewGRCPServerService creates a new ServerService with the appropriate logger etc.
|
|
||||||
func NewGRCPServerService(name string, server *grpc.Server, listener net.Listener, isTLS bool, log *logrus.Logger) (service *GRCPServerService) {
|
|
||||||
return &GRCPServerService{
|
|
||||||
name: name,
|
|
||||||
server: server,
|
|
||||||
listener: listener,
|
|
||||||
isTLS: isTLS,
|
|
||||||
log: log.WithFields(map[string]any{logFieldService: serviceTypeServer, serviceTypeServer: name}),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewFileWatcherService creates a new FileWatcherService with the appropriate logger etc.
|
// NewFileWatcherService creates a new FileWatcherService with the appropriate logger etc.
|
||||||
func NewFileWatcherService(name, path string, reload ProviderReload, log *logrus.Logger) (service *FileWatcherService, err error) {
|
func NewFileWatcherService(name, path string, reload ProviderReload, log *logrus.Logger) (service *FileWatcherService, err error) {
|
||||||
if path == "" {
|
if path == "" {
|
||||||
|
@ -173,54 +161,6 @@ func (service *ServerService) Log() *logrus.Entry {
|
||||||
return service.log
|
return service.log
|
||||||
}
|
}
|
||||||
|
|
||||||
// GRCPServerService is a Service which runs a gRCP server.
|
|
||||||
type GRCPServerService struct {
|
|
||||||
name string
|
|
||||||
server *grpc.Server
|
|
||||||
isTLS bool
|
|
||||||
listener net.Listener
|
|
||||||
log *logrus.Entry
|
|
||||||
}
|
|
||||||
|
|
||||||
// ServiceType returns the service type for this service, which is always 'server'.
|
|
||||||
func (service *GRCPServerService) ServiceType() string {
|
|
||||||
return serviceTypeServer
|
|
||||||
}
|
|
||||||
|
|
||||||
// ServiceName returns the individual name for this service.
|
|
||||||
func (service *GRCPServerService) ServiceName() string {
|
|
||||||
return service.name
|
|
||||||
}
|
|
||||||
|
|
||||||
// Run the ServerService.
|
|
||||||
func (service *GRCPServerService) Run() (err error) {
|
|
||||||
defer func() {
|
|
||||||
if r := recover(); r != nil {
|
|
||||||
service.log.WithError(recoverErr(r)).Error("Critical error caught (recovered)")
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
service.log.Infof(fmtLogServerListening, connectionType(service.isTLS), service.listener.Addr().String())
|
|
||||||
|
|
||||||
if err = service.server.Serve(service.listener); err != nil {
|
|
||||||
service.log.WithError(err).Error("Error returned attempting to serve requests")
|
|
||||||
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Shutdown the ServerService.
|
|
||||||
func (service *GRCPServerService) Shutdown() {
|
|
||||||
service.server.Stop()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Log returns the *logrus.Entry of the ServerService.
|
|
||||||
func (service *GRCPServerService) Log() *logrus.Entry {
|
|
||||||
return service.log
|
|
||||||
}
|
|
||||||
|
|
||||||
// FileWatcherService is a Service that watches files for changes.
|
// FileWatcherService is a Service that watches files for changes.
|
||||||
type FileWatcherService struct {
|
type FileWatcherService struct {
|
||||||
name string
|
name string
|
||||||
|
@ -332,19 +272,6 @@ func svcSvrMetricsFunc(ctx *CmdCtx) (service Service) {
|
||||||
return service
|
return service
|
||||||
}
|
}
|
||||||
|
|
||||||
func svcSvrGRPCFunc(ctx *CmdCtx) (service Service) {
|
|
||||||
switch svr, listener, isTLS, err := server.CreateGRPCServer(ctx.config, ctx.providers); {
|
|
||||||
case err != nil:
|
|
||||||
ctx.log.WithError(err).Fatal("Create Server Service (gRPC) returned error")
|
|
||||||
case svr != nil && listener != nil:
|
|
||||||
service = NewGRCPServerService("gRCP", svr, listener, isTLS, ctx.log)
|
|
||||||
default:
|
|
||||||
ctx.log.Debug("Create Server Service (gRPC) skipped")
|
|
||||||
}
|
|
||||||
|
|
||||||
return service
|
|
||||||
}
|
|
||||||
|
|
||||||
func svcWatcherUsersFunc(ctx *CmdCtx) (service Service) {
|
func svcWatcherUsersFunc(ctx *CmdCtx) (service Service) {
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
|
@ -385,7 +312,7 @@ func servicesRun(ctx *CmdCtx) {
|
||||||
)
|
)
|
||||||
|
|
||||||
for _, serviceFunc := range []func(ctx *CmdCtx) Service{
|
for _, serviceFunc := range []func(ctx *CmdCtx) Service{
|
||||||
svcSvrMainFunc, svcSvrGRPCFunc, svcSvrMetricsFunc,
|
svcSvrMainFunc, svcSvrMetricsFunc,
|
||||||
svcWatcherUsersFunc,
|
svcWatcherUsersFunc,
|
||||||
} {
|
} {
|
||||||
if service := serviceFunc(ctx); service != nil {
|
if service := serviceFunc(ctx); service != nil {
|
||||||
|
|
|
@ -35,11 +35,25 @@ type OpenIDConnect struct {
|
||||||
|
|
||||||
Clients []OpenIDConnectClient `koanf:"clients"`
|
Clients []OpenIDConnectClient `koanf:"clients"`
|
||||||
|
|
||||||
|
Policies map[string]OpenIDConnectPolicy `koanf:"policies"`
|
||||||
|
|
||||||
Discovery OpenIDConnectDiscovery // MetaData value. Not configurable by users.
|
Discovery OpenIDConnectDiscovery // MetaData value. Not configurable by users.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type OpenIDConnectPolicy struct {
|
||||||
|
DefaultPolicy string `koanf:"default_policy"`
|
||||||
|
|
||||||
|
Rules []OpenIDConnectPolicyRule `koanf:"rules"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type OpenIDConnectPolicyRule struct {
|
||||||
|
Policy string `koanf:"policy"`
|
||||||
|
Subjects [][]string `koanf:"subject"`
|
||||||
|
}
|
||||||
|
|
||||||
// OpenIDConnectDiscovery is information discovered during validation reused for the discovery handlers.
|
// OpenIDConnectDiscovery is information discovered during validation reused for the discovery handlers.
|
||||||
type OpenIDConnectDiscovery struct {
|
type OpenIDConnectDiscovery struct {
|
||||||
|
Policies []string
|
||||||
DefaultKeyIDs map[string]string
|
DefaultKeyIDs map[string]string
|
||||||
DefaultKeyID string
|
DefaultKeyID string
|
||||||
ResponseObjectSigningKeyIDs []string
|
ResponseObjectSigningKeyIDs []string
|
||||||
|
|
|
@ -72,6 +72,11 @@ var Keys = []string{
|
||||||
"identity_providers.oidc.clients[].public_keys.values[].key",
|
"identity_providers.oidc.clients[].public_keys.values[].key",
|
||||||
"identity_providers.oidc.clients[].public_keys.values[].certificate_chain",
|
"identity_providers.oidc.clients[].public_keys.values[].certificate_chain",
|
||||||
"identity_providers.oidc.clients[]",
|
"identity_providers.oidc.clients[]",
|
||||||
|
"identity_providers.oidc.policies",
|
||||||
|
"identity_providers.oidc.policies.*.default_policy",
|
||||||
|
"identity_providers.oidc.policies.*.rules",
|
||||||
|
"identity_providers.oidc.policies.*.rules[].policy",
|
||||||
|
"identity_providers.oidc.policies.*.rules[].subject",
|
||||||
"identity_providers.oidc",
|
"identity_providers.oidc",
|
||||||
"authentication_backend.password_reset.disable",
|
"authentication_backend.password_reset.disable",
|
||||||
"authentication_backend.password_reset.custom_url",
|
"authentication_backend.password_reset.custom_url",
|
||||||
|
@ -264,8 +269,6 @@ var Keys = []string{
|
||||||
"server.address",
|
"server.address",
|
||||||
"server.asset_path",
|
"server.asset_path",
|
||||||
"server.disable_healthcheck",
|
"server.disable_healthcheck",
|
||||||
"server.disable_autho_https_redirect",
|
|
||||||
"server.use_ip_for_ban",
|
|
||||||
"server.tls.certificate",
|
"server.tls.certificate",
|
||||||
"server.tls.key",
|
"server.tls.key",
|
||||||
"server.tls.client_certificates",
|
"server.tls.client_certificates",
|
||||||
|
@ -276,8 +279,6 @@ var Keys = []string{
|
||||||
"server.endpoints.authz.*.implementation",
|
"server.endpoints.authz.*.implementation",
|
||||||
"server.endpoints.authz.*.authn_strategies",
|
"server.endpoints.authz.*.authn_strategies",
|
||||||
"server.endpoints.authz.*.authn_strategies[].name",
|
"server.endpoints.authz.*.authn_strategies[].name",
|
||||||
"server.grpc.address",
|
|
||||||
"server.grpc.disableTLS",
|
|
||||||
"server.buffers.read",
|
"server.buffers.read",
|
||||||
"server.buffers.write",
|
"server.buffers.write",
|
||||||
"server.timeouts.read",
|
"server.timeouts.read",
|
||||||
|
|
|
@ -10,13 +10,10 @@ type ServerConfiguration struct {
|
||||||
Address *AddressTCP `koanf:"address"`
|
Address *AddressTCP `koanf:"address"`
|
||||||
AssetPath string `koanf:"asset_path"`
|
AssetPath string `koanf:"asset_path"`
|
||||||
DisableHealthcheck bool `koanf:"disable_healthcheck"`
|
DisableHealthcheck bool `koanf:"disable_healthcheck"`
|
||||||
DisableAutoHttpsRedirect bool `koanf:"disable_autho_https_redirect"`
|
|
||||||
UseIPInsteadOfUserForBan bool `koanf:"use_ip_for_ban"`
|
|
||||||
|
|
||||||
TLS ServerTLS `koanf:"tls"`
|
TLS ServerTLS `koanf:"tls"`
|
||||||
Headers ServerHeaders `koanf:"headers"`
|
Headers ServerHeaders `koanf:"headers"`
|
||||||
Endpoints ServerEndpoints `koanf:"endpoints"`
|
Endpoints ServerEndpoints `koanf:"endpoints"`
|
||||||
GRPC ServerGRPC `koanf:"grpc"`
|
|
||||||
|
|
||||||
Buffers ServerBuffers `koanf:"buffers"`
|
Buffers ServerBuffers `koanf:"buffers"`
|
||||||
Timeouts ServerTimeouts `koanf:"timeouts"`
|
Timeouts ServerTimeouts `koanf:"timeouts"`
|
||||||
|
@ -63,15 +60,6 @@ type ServerHeaders struct {
|
||||||
CSPTemplate string `koanf:"csp_template"`
|
CSPTemplate string `koanf:"csp_template"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ServerGRCP contains configuration options for the gRCP server.
|
|
||||||
type ServerGRPC struct {
|
|
||||||
// Address with port to listen on. If this field is empty, no grcp server
|
|
||||||
// will be spawned.
|
|
||||||
Address *AddressTCP `koanf:"address"`
|
|
||||||
|
|
||||||
DisableTLS bool `koanf:"disableTLS"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// DefaultServerConfiguration represents the default values of the ServerConfiguration.
|
// DefaultServerConfiguration represents the default values of the ServerConfiguration.
|
||||||
var DefaultServerConfiguration = ServerConfiguration{
|
var DefaultServerConfiguration = ServerConfiguration{
|
||||||
Address: &AddressTCP{Address{true, false, -1, 9091, &url.URL{Scheme: AddressSchemeTCP, Host: ":9091", Path: "/"}}},
|
Address: &AddressTCP{Address{true, false, -1, 9091, &url.URL{Scheme: AddressSchemeTCP, Host: ":9091", Path: "/"}}},
|
||||||
|
|
|
@ -124,6 +124,12 @@ notifier:
|
||||||
|
|
||||||
identity_providers:
|
identity_providers:
|
||||||
oidc:
|
oidc:
|
||||||
|
policies:
|
||||||
|
abc:
|
||||||
|
default_policy: 'two_factor'
|
||||||
|
rules:
|
||||||
|
- subject: 'group:admin'
|
||||||
|
policy: 'one_factor'
|
||||||
cors:
|
cors:
|
||||||
allowed_origins:
|
allowed_origins:
|
||||||
- 'https://google.com'
|
- 'https://google.com'
|
||||||
|
|
|
@ -30,6 +30,7 @@ func validateOIDC(config *schema.OpenIDConnect, val *schema.StructValidator) {
|
||||||
setOIDCDefaults(config)
|
setOIDCDefaults(config)
|
||||||
|
|
||||||
validateOIDCIssuer(config, val)
|
validateOIDCIssuer(config, val)
|
||||||
|
validateOIDCPolicies(config, val)
|
||||||
|
|
||||||
sort.Sort(oidc.SortedSigningAlgs(config.Discovery.ResponseObjectSigningAlgs))
|
sort.Sort(oidc.SortedSigningAlgs(config.Discovery.ResponseObjectSigningAlgs))
|
||||||
|
|
||||||
|
@ -58,6 +59,53 @@ func validateOIDC(config *schema.OpenIDConnect, val *schema.StructValidator) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func validateOIDCPolicies(config *schema.OpenIDConnect, val *schema.StructValidator) {
|
||||||
|
config.Discovery.Policies = []string{policyOneFactor, policyTwoFactor}
|
||||||
|
|
||||||
|
for name, policy := range config.Policies {
|
||||||
|
switch name {
|
||||||
|
case "":
|
||||||
|
val.Push(fmt.Errorf("policy must have a name"))
|
||||||
|
case policyOneFactor, policyTwoFactor, policyDeny:
|
||||||
|
val.Push(fmt.Errorf("policy names can't be named any of %s", strJoinAnd([]string{policyOneFactor, policyTwoFactor, policyDeny})))
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
switch policy.DefaultPolicy {
|
||||||
|
case "":
|
||||||
|
policy.DefaultPolicy = policyTwoFactor
|
||||||
|
case policyOneFactor, policyTwoFactor, policyDeny:
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
val.Push(fmt.Errorf("policy must be one of %s", strJoinAnd([]string{policyOneFactor, policyTwoFactor, policyDeny})))
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(policy.Rules) == 0 {
|
||||||
|
val.Push(fmt.Errorf("policy must include at least one rule"))
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, rule := range policy.Rules {
|
||||||
|
switch rule.Policy {
|
||||||
|
case "":
|
||||||
|
policy.Rules[i].Policy = policyTwoFactor
|
||||||
|
case policyOneFactor, policyTwoFactor, policyDeny:
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
val.Push(fmt.Errorf("policy must be one of %s", strJoinAnd([]string{policyOneFactor, policyTwoFactor, policyDeny})))
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(rule.Subjects) == 0 {
|
||||||
|
val.Push(fmt.Errorf("policy must include at least one criteria"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
config.Policies[name] = policy
|
||||||
|
|
||||||
|
config.Discovery.Policies = append(config.Discovery.Policies, name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func validateOIDCIssuer(config *schema.OpenIDConnect, val *schema.StructValidator) {
|
func validateOIDCIssuer(config *schema.OpenIDConnect, val *schema.StructValidator) {
|
||||||
switch {
|
switch {
|
||||||
case config.IssuerPrivateKey != nil:
|
case config.IssuerPrivateKey != nil:
|
||||||
|
@ -337,13 +385,13 @@ func validateOIDCClient(c int, config *schema.OpenIDConnect, val *schema.StructV
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
switch config.Clients[c].Policy {
|
switch {
|
||||||
case "":
|
case config.Clients[c].Policy == "":
|
||||||
config.Clients[c].Policy = schema.DefaultOpenIDConnectClientConfiguration.Policy
|
config.Clients[c].Policy = schema.DefaultOpenIDConnectClientConfiguration.Policy
|
||||||
case policyOneFactor, policyTwoFactor:
|
case utils.IsStringInSlice(config.Clients[c].Policy, config.Discovery.Policies):
|
||||||
break
|
break
|
||||||
default:
|
default:
|
||||||
val.Push(fmt.Errorf(errFmtOIDCClientInvalidValue, config.Clients[c].ID, "authorization_policy", strJoinOr([]string{policyOneFactor, policyTwoFactor}), config.Clients[c].Policy))
|
val.Push(fmt.Errorf(errFmtOIDCClientInvalidValue, config.Clients[c].ID, "authorization_policy", strJoinOr(config.Discovery.Policies), config.Clients[c].Policy))
|
||||||
}
|
}
|
||||||
|
|
||||||
switch config.Clients[c].PKCEChallengeMethod {
|
switch config.Clients[c].PKCEChallengeMethod {
|
||||||
|
|
|
@ -67,16 +67,18 @@ KEYS:
|
||||||
// NewKeyPattern returns patterns which are required to match key patterns.
|
// NewKeyPattern returns patterns which are required to match key patterns.
|
||||||
func NewKeyPattern(key string) (pattern *regexp.Regexp, err error) {
|
func NewKeyPattern(key string) (pattern *regexp.Regexp, err error) {
|
||||||
switch {
|
switch {
|
||||||
case strings.Contains(key, ".*."):
|
case reIsMapKey.MatchString(key):
|
||||||
return NewKeyMapPattern(key)
|
return NewKeyMapPattern(key)
|
||||||
default:
|
default:
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var reIsMapKey = regexp.MustCompile(`\.\*(\[]|\.)`)
|
||||||
|
|
||||||
// NewKeyMapPattern returns a pattern required to match map keys.
|
// NewKeyMapPattern returns a pattern required to match map keys.
|
||||||
func NewKeyMapPattern(key string) (pattern *regexp.Regexp, err error) {
|
func NewKeyMapPattern(key string) (pattern *regexp.Regexp, err error) {
|
||||||
parts := strings.Split(key, ".*.")
|
parts := strings.Split(key, ".*")
|
||||||
|
|
||||||
buf := &strings.Builder{}
|
buf := &strings.Builder{}
|
||||||
|
|
||||||
|
@ -85,11 +87,16 @@ func NewKeyMapPattern(key string) (pattern *regexp.Regexp, err error) {
|
||||||
n := len(parts) - 1
|
n := len(parts) - 1
|
||||||
|
|
||||||
for i, part := range parts {
|
for i, part := range parts {
|
||||||
if i != 0 {
|
if i != 0 && !strings.HasPrefix(part, "[]") {
|
||||||
buf.WriteString("\\.")
|
buf.WriteString("\\.")
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, r := range part {
|
for j, r := range part {
|
||||||
|
// Skip prefixed period.
|
||||||
|
if j == 0 && r == '.' {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
switch r {
|
switch r {
|
||||||
case '[', ']', '.', '{', '}':
|
case '[', ']', '.', '{', '}':
|
||||||
buf.WriteRune('\\')
|
buf.WriteRune('\\')
|
||||||
|
|
|
@ -1,410 +0,0 @@
|
||||||
package handlers
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"net"
|
|
||||||
"net/url"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/authelia/authelia/v4/internal/authorization"
|
|
||||||
"github.com/authelia/authelia/v4/internal/configuration/schema"
|
|
||||||
"github.com/authelia/authelia/v4/internal/middlewares"
|
|
||||||
"github.com/authelia/authelia/v4/internal/session"
|
|
||||||
"github.com/authelia/authelia/v4/internal/utils"
|
|
||||||
core "github.com/envoyproxy/go-control-plane/envoy/config/core/v3"
|
|
||||||
autha "github.com/envoyproxy/go-control-plane/envoy/service/auth/v3"
|
|
||||||
envoy_type "github.com/envoyproxy/go-control-plane/envoy/type/v3"
|
|
||||||
"github.com/gogo/googleapis/google/rpc"
|
|
||||||
"github.com/valyala/fasthttp"
|
|
||||||
rpcstatus "google.golang.org/genproto/googleapis/rpc/status"
|
|
||||||
"google.golang.org/grpc/codes"
|
|
||||||
healthpb "google.golang.org/grpc/health/grpc_health_v1"
|
|
||||||
"google.golang.org/grpc/status"
|
|
||||||
|
|
||||||
"context"
|
|
||||||
)
|
|
||||||
|
|
||||||
type AuthzGRCP struct {
|
|
||||||
Config *schema.Configuration
|
|
||||||
Providers middlewares.Providers
|
|
||||||
AuthStrategies []AuthnStrategy
|
|
||||||
Authz Authz
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewAuthzGRCP(config *schema.Configuration, providers middlewares.Providers) *AuthzGRCP {
|
|
||||||
|
|
||||||
// Determine the refresh interval
|
|
||||||
authBuilder := NewAuthzBuilder().WithConfig(config)
|
|
||||||
|
|
||||||
// Only the following strategies are supported. These are hardcoded at the moment and won't be taken from the configuration
|
|
||||||
strategies := []AuthnStrategy{NewHeaderProxyAuthorizationAuthnStrategy() /* NewHeaderAuthorizationAuthnStrategy(), */, NewCookieSessionAuthnStrategy(authBuilder.config.RefreshInterval)}
|
|
||||||
|
|
||||||
return &AuthzGRCP{
|
|
||||||
Config: config,
|
|
||||||
Providers: providers,
|
|
||||||
AuthStrategies: strategies,
|
|
||||||
Authz: Authz{strategies: strategies},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type GRCPRequestData struct {
|
|
||||||
RemoteHost string
|
|
||||||
Domain string
|
|
||||||
Method string
|
|
||||||
Protocol string
|
|
||||||
Path string
|
|
||||||
AutheliaURL string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (data *GRCPRequestData) String() string {
|
|
||||||
return fmt.Sprintf(
|
|
||||||
`Extracted data from headers:
|
|
||||||
Remote Host = %s
|
|
||||||
Domain = %s
|
|
||||||
Method = %s
|
|
||||||
Protocol = %s
|
|
||||||
Path = %s
|
|
||||||
AutheliaURL = %s
|
|
||||||
`, data.RemoteHost, data.Domain, data.Method, data.Protocol, data.Path, data.AutheliaURL)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetRequestURI returns a request URI from the provided Data inside this struct.
|
|
||||||
// It returns an error if values are missing
|
|
||||||
func (data *GRCPRequestData) GetRequestURI() (*url.URL, error) {
|
|
||||||
if len(data.Protocol) == 0 || len(data.Domain) == 0 || len(data.Path) == 0 || len(data.Method) == 0 {
|
|
||||||
return nil, fmt.Errorf("missing required values for URI. One of 'Protocol', 'Domain', 'Path' or 'Method' was not found")
|
|
||||||
}
|
|
||||||
|
|
||||||
return url.ParseRequestURI(fmt.Sprintf("%s://%s%s", data.Protocol, data.Domain, data.Path))
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetAutheliaURI returns a URI for the authelia protal from the provided Data inside this struct.
|
|
||||||
func (data *GRCPRequestData) GetAutheliaURI(provider *session.Session) (*url.URL, error) {
|
|
||||||
if len(data.AutheliaURL) == 0 {
|
|
||||||
return nil, fmt.Errorf("missing required 'AutheliaURL' for request")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse the URL
|
|
||||||
uri, err := url.ParseRequestURI(data.AutheliaURL)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Validate URL
|
|
||||||
if !utils.HasURIDomainSuffix(uri, provider.Config.Domain) {
|
|
||||||
return nil, fmt.Errorf("authelia url '%s' is not valid for detected domain '%s' as the url does not have the domain as a suffix", data.AutheliaURL, provider.Config.Domain)
|
|
||||||
}
|
|
||||||
|
|
||||||
return uri, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// HandleGRPC is the authentication handler for envoy proxies via the gRPC protocoll.
|
|
||||||
// It is oriented on handler_authz.go
|
|
||||||
func (authz *AuthzGRCP) Check(goCtx context.Context, req *autha.CheckRequest) (*autha.CheckResponse, error) {
|
|
||||||
request, data := authz.GetHttpCtxFromGRPC(req)
|
|
||||||
ctx := middlewares.NewAutheliaCtx(request, *authz.Config, authz.Providers)
|
|
||||||
|
|
||||||
// Log the parsed data and the inbound headers
|
|
||||||
ctx.Logger.Debug(data)
|
|
||||||
b, err := json.MarshalIndent(req.Attributes.Request.Http.Headers, "", " ")
|
|
||||||
if err == nil {
|
|
||||||
ctx.Logger.Trace("Inbound Headers: ")
|
|
||||||
ctx.Logger.Trace((string(b)))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get request URI
|
|
||||||
uri, err := data.GetRequestURI()
|
|
||||||
if err != nil {
|
|
||||||
ctx.Logger.WithError(err).Error("Error getting Target URL and Request Method")
|
|
||||||
return authz.ErrAuthResponse(envoy_type.StatusCode_BadRequest, "Bad authentication request"), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get authentication object
|
|
||||||
object := authorization.NewObject(uri, data.Method)
|
|
||||||
if !utils.IsURISecure(object.URL) {
|
|
||||||
// Check for redirect
|
|
||||||
if !ctx.Configuration.Server.DisableAutoHttpsRedirect {
|
|
||||||
// Redirect to https
|
|
||||||
return authz.AuthResponseHeader(envoy_type.StatusCode_PermanentRedirect, "", []*core.HeaderValueOption{
|
|
||||||
{
|
|
||||||
Header: &core.HeaderValue{
|
|
||||||
Key: "Location",
|
|
||||||
Value: fmt.Sprintf("https://%s%s", data.Domain, data.Path),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}), nil
|
|
||||||
}
|
|
||||||
ctx.Logger.Errorf("Target URL '%s' has an insecure scheme '%s', only the 'https' and 'wss' schemes are supported so session cookies can be transmitted securely", object.URL.String(), object.URL.Scheme)
|
|
||||||
return authz.ErrAuthResponse(envoy_type.StatusCode_BadRequest, "Bad protocol for authentication request"), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get provider
|
|
||||||
provider, err := ctx.GetSessionProviderByTargetURL(object.URL)
|
|
||||||
if err != nil {
|
|
||||||
ctx.Logger.WithError(err).WithField("target_url", object.URL.String()).Error("Target URL does not appear to have a relevant session cookies configuration")
|
|
||||||
return authz.ErrAuthResponse(envoy_type.StatusCode_BadRequest, "Bad domain for authentication request"), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get authelia url
|
|
||||||
if len(data.AutheliaURL) == 0 {
|
|
||||||
ctx.Logger.Info("Received no authelia URL from headers. Using the default of https://auth.rpjosh.de")
|
|
||||||
data.AutheliaURL = "https://auth.rpjosh.de"
|
|
||||||
}
|
|
||||||
autheliaURI, err := data.GetAutheliaURI(provider)
|
|
||||||
if err != nil {
|
|
||||||
ctx.Logger.WithError(err).WithField("target_url", object.URL.String()).Error("Error occurred trying to determine the external Authelia URL for Target URL")
|
|
||||||
return authz.ErrAuthResponse(envoy_type.StatusCode_BadRequest, "Bad authentication request"), nil
|
|
||||||
}
|
|
||||||
ctx.Logger.Trace("Using authelia URL " + autheliaURI.String())
|
|
||||||
|
|
||||||
var (
|
|
||||||
authn Authn
|
|
||||||
strategy AuthnStrategy
|
|
||||||
)
|
|
||||||
|
|
||||||
// Get strategie
|
|
||||||
if authn, strategy, err = authz.Authz.authn(ctx, provider); err != nil {
|
|
||||||
authn.Object = object
|
|
||||||
|
|
||||||
ctx.Logger.WithError(err).Error("Error occurred while attempting to authenticate a request")
|
|
||||||
|
|
||||||
switch strategy {
|
|
||||||
case nil:
|
|
||||||
ctx.Logger.Trace("Received no strategy to use")
|
|
||||||
return authz.ErrAuthResponse(envoy_type.StatusCode_Unauthorized, "Unauthorized"), nil
|
|
||||||
default:
|
|
||||||
// Because the response is modified directly, we have to catch this and rewrite this function
|
|
||||||
if s, ok := strategy.(*HeaderAuthnStrategy); ok {
|
|
||||||
ctx.Logger.Trace("Rewriting HeaderAuthnStrategy")
|
|
||||||
ctx.Logger.Debugf("Responding %d %s", s.authn, autheliaURI)
|
|
||||||
|
|
||||||
headers := make([]*core.HeaderValueOption, 0)
|
|
||||||
if s.headerAuthenticate != nil {
|
|
||||||
headers = append(headers, &core.HeaderValueOption{
|
|
||||||
Header: &core.HeaderValue{
|
|
||||||
Key: string(s.headerAuthenticate),
|
|
||||||
Value: string(headerValueAuthenticateBasic),
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
return authz.AuthResponseHeader(envoy_type.StatusCode(s.statusAuthenticate), "", headers), nil
|
|
||||||
} else if _, ok := strategy.(*CookieSessionAuthnStrategy); ok {
|
|
||||||
ctx.Logger.Trace("Rewriting CookieSessionAuthnStrategy")
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx.Logger.Error("Received unsupported auth strategy for gRPC server")
|
|
||||||
// strategy.HandleUnauthorized(ctx, &authn, authz.Authz.getRedirectionURL(&object, autheliaURI))
|
|
||||||
}
|
|
||||||
|
|
||||||
return authz.ErrAuthResponse(envoy_type.StatusCode_Unauthorized, "Unauthorized"), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
authn.Object = object
|
|
||||||
authn.Method = friendlyMethod(authn.Object.Method)
|
|
||||||
|
|
||||||
ruleHasSubject, required := ctx.Providers.Authorizer.GetRequiredLevel(
|
|
||||||
authorization.Subject{
|
|
||||||
Username: authn.Details.Username,
|
|
||||||
Groups: authn.Details.Groups,
|
|
||||||
IP: net.ParseIP(data.RemoteHost),
|
|
||||||
},
|
|
||||||
object,
|
|
||||||
)
|
|
||||||
|
|
||||||
switch isAuthzResult(authn.Level, required, ruleHasSubject) {
|
|
||||||
case AuthzResultForbidden:
|
|
||||||
ctx.Logger.Infof("Access to '%s' is forbidden to user '%s'", object.URL.String(), authn.Username)
|
|
||||||
return authz.ErrAuthResponse(envoy_type.StatusCode_Forbidden, "Forbidden"), nil
|
|
||||||
case AuthzResultUnauthorized:
|
|
||||||
if strategy != nil {
|
|
||||||
ctx.Logger.Error("Handling not supported handler")
|
|
||||||
//strategy.HandleUnauthorized(ctx, &authn, authz.Authz.getRedirectionURL(&object, autheliaURI))
|
|
||||||
} else {
|
|
||||||
ctx.Logger.Debugf("Redirecting user")
|
|
||||||
return authz.HandleUnauthorizedRedirect(ctx, &authn, authz.Authz.getRedirectionURL(&object, autheliaURI)), nil
|
|
||||||
}
|
|
||||||
case AuthzResultAuthorized:
|
|
||||||
ctx.Logger.Debugf("Authorized request")
|
|
||||||
return authz.HandleAuthorized(ctx, &authn), nil
|
|
||||||
//authz.Authz.handleAuthorized(ctx, &authn)
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx.Logger.Info("Handling default redirection")
|
|
||||||
return authz.HandleUnauthorizedRedirect(ctx, &authn, authz.Authz.getRedirectionURL(&object, autheliaURI)), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetHttpCtxFromGRPC is an Adapter that converts common fields between a grpc request
|
|
||||||
// a "normal" http request.
|
|
||||||
// It also returns the
|
|
||||||
func (authz *AuthzGRCP) GetHttpCtxFromGRPC(req *autha.CheckRequest) (*fasthttp.RequestCtx, *GRCPRequestData) {
|
|
||||||
|
|
||||||
// Extract headers
|
|
||||||
headers := req.Attributes.Request.Http.Headers
|
|
||||||
|
|
||||||
// Parse the header data
|
|
||||||
data := &GRCPRequestData{
|
|
||||||
RemoteHost: headers["x-forwarded-for"],
|
|
||||||
Domain: headers[":authority"],
|
|
||||||
Method: headers[":method"],
|
|
||||||
Protocol: headers["x-forwarded-proto"],
|
|
||||||
Path: headers[":path"],
|
|
||||||
AutheliaURL: headers[""],
|
|
||||||
}
|
|
||||||
|
|
||||||
// Build fasthttp request with common types
|
|
||||||
rtc := &fasthttp.RequestCtx{}
|
|
||||||
|
|
||||||
// General headers
|
|
||||||
rtc.Request.Header.Set(fasthttp.HeaderXForwardedFor, data.RemoteHost)
|
|
||||||
|
|
||||||
// Needed for NewHeaderProxyAuthorizationAuthnStrategy and NewHeaderAuthorizationAuthnStrategy
|
|
||||||
authz.setHeaderIfSet(fasthttp.HeaderAuthorization, rtc, &headers)
|
|
||||||
authz.setHeaderIfSet(fasthttp.HeaderProxyAuthorization, rtc, &headers)
|
|
||||||
authz.setHeaderIfSet(fasthttp.HeaderWWWAuthenticate, rtc, &headers)
|
|
||||||
authz.setHeaderIfSet(fasthttp.HeaderProxyAuthenticate, rtc, &headers)
|
|
||||||
|
|
||||||
// Needed for CookieSesseionauthnStrategy
|
|
||||||
rtc.Request.Header.Set("cookie", headers["cookie"])
|
|
||||||
|
|
||||||
return rtc, data
|
|
||||||
}
|
|
||||||
|
|
||||||
// setHeaderIfSet sets the header in the given fastHttp request if the header from the envoy authentication
|
|
||||||
// request was also set
|
|
||||||
func (authz *AuthzGRCP) setHeaderIfSet(headerKeyFast string, rtc *fasthttp.RequestCtx, envoyHeaders *map[string]string) {
|
|
||||||
// Envoys provided header keys are always lower case
|
|
||||||
envoyHeaderKey := strings.ToLower(headerKeyFast)
|
|
||||||
|
|
||||||
if val, isSet := (*envoyHeaders)[envoyHeaderKey]; isSet {
|
|
||||||
rtc.Request.Header.Set(headerKeyFast, val)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ErrAuthResponse returns an authentication error for envoy with the given status code
|
|
||||||
// and the given text body
|
|
||||||
func (authz *AuthzGRCP) ErrAuthResponse(statuscode envoy_type.StatusCode, body string) *autha.CheckResponse {
|
|
||||||
return &autha.CheckResponse{
|
|
||||||
Status: &rpcstatus.Status{
|
|
||||||
Code: int32(rpc.UNAUTHENTICATED),
|
|
||||||
},
|
|
||||||
HttpResponse: &autha.CheckResponse_DeniedResponse{
|
|
||||||
DeniedResponse: &autha.DeniedHttpResponse{
|
|
||||||
Status: &envoy_type.HttpStatus{
|
|
||||||
Code: statuscode,
|
|
||||||
},
|
|
||||||
Body: body,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ErrAuthResponse returns an authentication error for envoy with the given status code
|
|
||||||
// and the given text body
|
|
||||||
func (authz *AuthzGRCP) AuthResponseHeader(statuscode envoy_type.StatusCode, body string, headers []*core.HeaderValueOption) *autha.CheckResponse {
|
|
||||||
return &autha.CheckResponse{
|
|
||||||
Status: &rpcstatus.Status{
|
|
||||||
Code: int32(rpc.UNAUTHENTICATED),
|
|
||||||
},
|
|
||||||
HttpResponse: &autha.CheckResponse_DeniedResponse{
|
|
||||||
DeniedResponse: &autha.DeniedHttpResponse{
|
|
||||||
Status: &envoy_type.HttpStatus{
|
|
||||||
Code: statuscode,
|
|
||||||
},
|
|
||||||
Body: body,
|
|
||||||
Headers: headers,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (authz *AuthzGRCP) HandleAuthorized(ctx *middlewares.AutheliaCtx, authn *Authn) *autha.CheckResponse {
|
|
||||||
return &autha.CheckResponse{
|
|
||||||
Status: &rpcstatus.Status{
|
|
||||||
Code: int32(rpc.OK),
|
|
||||||
},
|
|
||||||
HttpResponse: &autha.CheckResponse_OkResponse{
|
|
||||||
OkResponse: &autha.OkHttpResponse{
|
|
||||||
Headers: []*core.HeaderValueOption{
|
|
||||||
{
|
|
||||||
Header: &core.HeaderValue{
|
|
||||||
Key: "Auth-Handler",
|
|
||||||
Value: getAuthType(authn.Type),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Header: &core.HeaderValue{
|
|
||||||
Key: "Auth-Username",
|
|
||||||
Value: authn.Username,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Header: &core.HeaderValue{
|
|
||||||
Key: "Auth-Username-Display",
|
|
||||||
Value: authn.Details.DisplayName,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Header: &core.HeaderValue{
|
|
||||||
Key: "Auth-Realm",
|
|
||||||
Value: authn.Object.Domain,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (authz *AuthzGRCP) HandleUnauthorizedRedirect(ctx *middlewares.AutheliaCtx, authn *Authn, redirectionURL *url.URL) *autha.CheckResponse {
|
|
||||||
return &autha.CheckResponse{
|
|
||||||
Status: &rpcstatus.Status{
|
|
||||||
Code: int32(rpc.UNAUTHENTICATED),
|
|
||||||
},
|
|
||||||
HttpResponse: &autha.CheckResponse_DeniedResponse{
|
|
||||||
DeniedResponse: &autha.DeniedHttpResponse{
|
|
||||||
Status: &envoy_type.HttpStatus{
|
|
||||||
Code: 302,
|
|
||||||
},
|
|
||||||
Headers: []*core.HeaderValueOption{
|
|
||||||
{
|
|
||||||
Header: &core.HeaderValue{
|
|
||||||
Key: "Location",
|
|
||||||
Value: redirectionURL.String(),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func getAuthType(t AuthnType) string {
|
|
||||||
|
|
||||||
switch t {
|
|
||||||
case AuthnTypeNone:
|
|
||||||
return "none"
|
|
||||||
case AuthnTypeCookie:
|
|
||||||
return "cookie"
|
|
||||||
case AuthnTypeProxyAuthorization:
|
|
||||||
return "proxy"
|
|
||||||
case AuthnTypeAuthorization:
|
|
||||||
return "header"
|
|
||||||
default:
|
|
||||||
return "unknown"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// HealthEndpoint implements a health function to check if the appliction is
|
|
||||||
// still alive
|
|
||||||
type HealthEndpoint struct{}
|
|
||||||
|
|
||||||
func (s *HealthEndpoint) Check(ctx context.Context, in *healthpb.HealthCheckRequest) (*healthpb.HealthCheckResponse, error) {
|
|
||||||
return &healthpb.HealthCheckResponse{Status: healthpb.HealthCheckResponse_SERVING}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *HealthEndpoint) Watch(in *healthpb.HealthCheckRequest, srv healthpb.Health_WatchServer) error {
|
|
||||||
return status.Error(codes.Unimplemented, "Watch is not implemented")
|
|
||||||
}
|
|
|
@ -33,7 +33,7 @@ func FirstFactorPOST(delayFunc middlewares.TimingAttackDelayFunc) middlewares.Re
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if bannedUntil, err := ctx.Providers.Regulator.Regulate(ctx, bodyJSON.Username, ctx.RemoteIP().String()); err != nil {
|
if bannedUntil, err := ctx.Providers.Regulator.Regulate(ctx, bodyJSON.Username); err != nil {
|
||||||
if errors.Is(err, regulation.ErrUserIsBanned) {
|
if errors.Is(err, regulation.ErrUserIsBanned) {
|
||||||
_ = markAuthenticationAttempt(ctx, false, &bannedUntil, bodyJSON.Username, regulation.AuthType1FA, nil)
|
_ = markAuthenticationAttempt(ctx, false, &bannedUntil, bodyJSON.Username, regulation.AuthType1FA, nil)
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,7 @@ import (
|
||||||
|
|
||||||
"github.com/ory/fosite"
|
"github.com/ory/fosite"
|
||||||
|
|
||||||
|
"github.com/authelia/authelia/v4/internal/authorization"
|
||||||
"github.com/authelia/authelia/v4/internal/middlewares"
|
"github.com/authelia/authelia/v4/internal/middlewares"
|
||||||
"github.com/authelia/authelia/v4/internal/model"
|
"github.com/authelia/authelia/v4/internal/model"
|
||||||
"github.com/authelia/authelia/v4/internal/oidc"
|
"github.com/authelia/authelia/v4/internal/oidc"
|
||||||
|
@ -117,7 +118,7 @@ func OpenIDConnectAuthorization(ctx *middlewares.AutheliaCtx, rw http.ResponseWr
|
||||||
|
|
||||||
extraClaims := oidcGrantRequests(requester, consent, &userSession)
|
extraClaims := oidcGrantRequests(requester, consent, &userSession)
|
||||||
|
|
||||||
if authTime, err = userSession.AuthenticatedTime(client.GetAuthorizationPolicy()); err != nil {
|
if authTime, err = userSession.AuthenticatedTime(client.GetAuthorizationPolicy(authorization.Subject{Username: userSession.Username, Groups: userSession.Groups, IP: ctx.RemoteIP()})); err != nil {
|
||||||
ctx.Logger.Errorf("Authorization Request with id '%s' on client with id '%s' could not be processed: error occurred checking authentication time: %+v", requester.GetID(), client.GetID(), err)
|
ctx.Logger.Errorf("Authorization Request with id '%s' on client with id '%s' could not be processed: error occurred checking authentication time: %+v", requester.GetID(), client.GetID(), err)
|
||||||
|
|
||||||
ctx.Providers.OpenIDConnect.WriteAuthorizeError(ctx, rw, requester, fosite.ErrServerError.WithHint("Could not obtain the authentication time."))
|
ctx.Providers.OpenIDConnect.WriteAuthorizeError(ctx, rw, requester, fosite.ErrServerError.WithHint("Could not obtain the authentication time."))
|
||||||
|
|
|
@ -11,6 +11,7 @@ import (
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
"github.com/ory/fosite"
|
"github.com/ory/fosite"
|
||||||
|
|
||||||
|
"github.com/authelia/authelia/v4/internal/authorization"
|
||||||
"github.com/authelia/authelia/v4/internal/middlewares"
|
"github.com/authelia/authelia/v4/internal/middlewares"
|
||||||
"github.com/authelia/authelia/v4/internal/model"
|
"github.com/authelia/authelia/v4/internal/model"
|
||||||
"github.com/authelia/authelia/v4/internal/oidc"
|
"github.com/authelia/authelia/v4/internal/oidc"
|
||||||
|
@ -28,10 +29,12 @@ func handleOIDCAuthorizationConsent(ctx *middlewares.AutheliaCtx, issuer *url.UR
|
||||||
|
|
||||||
var handler handlerAuthorizationConsent
|
var handler handlerAuthorizationConsent
|
||||||
|
|
||||||
|
policy := client.GetAuthorizationPolicy(authorization.Subject{Username: userSession.Username, Groups: userSession.Groups, IP: ctx.RemoteIP()})
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
case userSession.IsAnonymous():
|
case userSession.IsAnonymous():
|
||||||
handler = handleOIDCAuthorizationConsentNotAuthenticated
|
handler = handleOIDCAuthorizationConsentNotAuthenticated
|
||||||
case client.IsAuthenticationLevelSufficient(userSession.AuthenticationLevel):
|
case authorization.IsAuthLevelSufficient(userSession.AuthenticationLevel, policy):
|
||||||
if subject, err = ctx.Providers.OpenIDConnect.GetSubject(ctx, client.GetSectorIdentifier(), userSession.Username); err != nil {
|
if subject, err = ctx.Providers.OpenIDConnect.GetSubject(ctx, client.GetSectorIdentifier(), userSession.Username); err != nil {
|
||||||
ctx.Logger.Errorf(logFmtErrConsentCantGetSubject, requester.GetID(), client.GetID(), client.GetConsentPolicy(), userSession.Username, client.GetSectorIdentifier(), err)
|
ctx.Logger.Errorf(logFmtErrConsentCantGetSubject, requester.GetID(), client.GetID(), client.GetConsentPolicy(), userSession.Username, client.GetSectorIdentifier(), err)
|
||||||
|
|
||||||
|
@ -55,6 +58,14 @@ func handleOIDCAuthorizationConsent(ctx *middlewares.AutheliaCtx, issuer *url.UR
|
||||||
return nil, true
|
return nil, true
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
if policy == authorization.Denied {
|
||||||
|
ctx.Logger.Errorf("Authorization Request with id '%s' on client with id '%s' could not be processed: the user '%s' is not authorized to use this client", requester.GetID(), client.GetID(), userSession.Username)
|
||||||
|
|
||||||
|
ctx.Providers.OpenIDConnect.WriteAuthorizeError(ctx, rw, requester, oidc.ErrClientAuthorizationUserAccessDenied)
|
||||||
|
|
||||||
|
return nil, true
|
||||||
|
}
|
||||||
|
|
||||||
if subject, err = ctx.Providers.OpenIDConnect.GetSubject(ctx, client.GetSectorIdentifier(), userSession.Username); err != nil {
|
if subject, err = ctx.Providers.OpenIDConnect.GetSubject(ctx, client.GetSectorIdentifier(), userSession.Username); err != nil {
|
||||||
ctx.Logger.Errorf(logFmtErrConsentCantGetSubject, requester.GetID(), client.GetID(), client.GetConsentPolicy(), userSession.Username, client.GetSectorIdentifier(), err)
|
ctx.Logger.Errorf(logFmtErrConsentCantGetSubject, requester.GetID(), client.GetID(), client.GetConsentPolicy(), userSession.Username, client.GetSectorIdentifier(), err)
|
||||||
|
|
||||||
|
@ -121,7 +132,7 @@ func handleOIDCAuthorizationConsentRedirect(ctx *middlewares.AutheliaCtx, issuer
|
||||||
userSession session.UserSession, rw http.ResponseWriter, r *http.Request, requester fosite.AuthorizeRequester) {
|
userSession session.UserSession, rw http.ResponseWriter, r *http.Request, requester fosite.AuthorizeRequester) {
|
||||||
var location *url.URL
|
var location *url.URL
|
||||||
|
|
||||||
if client.IsAuthenticationLevelSufficient(userSession.AuthenticationLevel) {
|
if client.IsAuthenticationLevelSufficient(userSession.AuthenticationLevel, authorization.Subject{Username: userSession.Username, Groups: userSession.Groups, IP: ctx.RemoteIP()}) {
|
||||||
location, _ = url.ParseRequestURI(issuer.String())
|
location, _ = url.ParseRequestURI(issuer.String())
|
||||||
location.Path = path.Join(location.Path, oidc.EndpointPathConsent)
|
location.Path = path.Join(location.Path, oidc.EndpointPathConsent)
|
||||||
|
|
||||||
|
@ -130,11 +141,11 @@ func handleOIDCAuthorizationConsentRedirect(ctx *middlewares.AutheliaCtx, issuer
|
||||||
|
|
||||||
location.RawQuery = query.Encode()
|
location.RawQuery = query.Encode()
|
||||||
|
|
||||||
ctx.Logger.Debugf(logFmtDbgConsentAuthenticationSufficiency, requester.GetID(), client.GetID(), client.GetConsentPolicy(), userSession.AuthenticationLevel.String(), "sufficient", client.GetAuthorizationPolicy())
|
ctx.Logger.Debugf(logFmtDbgConsentAuthenticationSufficiency, requester.GetID(), client.GetID(), client.GetConsentPolicy(), userSession.AuthenticationLevel.String(), "sufficient", client.GetAuthorizationPolicy(authorization.Subject{Username: userSession.Username, Groups: userSession.Groups, IP: ctx.RemoteIP()}))
|
||||||
} else {
|
} else {
|
||||||
location = handleOIDCAuthorizationConsentGetRedirectionURL(issuer, consent, requester)
|
location = handleOIDCAuthorizationConsentGetRedirectionURL(issuer, consent, requester)
|
||||||
|
|
||||||
ctx.Logger.Debugf(logFmtDbgConsentAuthenticationSufficiency, requester.GetID(), client.GetID(), client.GetConsentPolicy(), userSession.AuthenticationLevel.String(), "insufficient", client.GetAuthorizationPolicy())
|
ctx.Logger.Debugf(logFmtDbgConsentAuthenticationSufficiency, requester.GetID(), client.GetID(), client.GetConsentPolicy(), userSession.AuthenticationLevel.String(), "insufficient", client.GetAuthorizationPolicy(authorization.Subject{Username: userSession.Username, Groups: userSession.Groups, IP: ctx.RemoteIP()}))
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.Logger.Debugf(logFmtDbgConsentRedirect, requester.GetID(), client.GetID(), client.GetConsentPolicy(), location)
|
ctx.Logger.Debugf(logFmtDbgConsentRedirect, requester.GetID(), client.GetID(), client.GetConsentPolicy(), location)
|
||||||
|
|
|
@ -10,6 +10,7 @@ import (
|
||||||
|
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
|
|
||||||
|
"github.com/authelia/authelia/v4/internal/authorization"
|
||||||
"github.com/authelia/authelia/v4/internal/middlewares"
|
"github.com/authelia/authelia/v4/internal/middlewares"
|
||||||
"github.com/authelia/authelia/v4/internal/model"
|
"github.com/authelia/authelia/v4/internal/model"
|
||||||
"github.com/authelia/authelia/v4/internal/oidc"
|
"github.com/authelia/authelia/v4/internal/oidc"
|
||||||
|
@ -86,6 +87,14 @@ func OpenIDConnectConsentPOST(ctx *middlewares.AutheliaCtx) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !client.IsAuthenticationLevelSufficient(userSession.AuthenticationLevel, authorization.Subject{Username: userSession.Username, Groups: userSession.Groups, IP: ctx.RemoteIP()}) {
|
||||||
|
ctx.Logger.Errorf("User '%s' can't consent to authorization request for client with id '%s' as they are not sufficiently authenticated",
|
||||||
|
userSession.Username, consent.ClientID)
|
||||||
|
ctx.SetJSONError(messageOperationFailed)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if bodyJSON.Consent {
|
if bodyJSON.Consent {
|
||||||
consent.Grant()
|
consent.Grant()
|
||||||
|
|
||||||
|
@ -206,7 +215,7 @@ func oidcConsentGetSessionsAndClient(ctx *middlewares.AutheliaCtx, consentID uui
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !client.IsAuthenticationLevelSufficient(userSession.AuthenticationLevel) {
|
if !client.IsAuthenticationLevelSufficient(userSession.AuthenticationLevel, authorization.Subject{Username: userSession.Username, Groups: userSession.Groups, IP: ctx.RemoteIP()}) {
|
||||||
ctx.Logger.Errorf("Unable to perform OpenID Connect Consent for user '%s' and client id '%s': the user is not sufficiently authenticated", userSession.Username, consent.ClientID)
|
ctx.Logger.Errorf("Unable to perform OpenID Connect Consent for user '%s' and client id '%s': the user is not sufficiently authenticated", userSession.Username, consent.ClientID)
|
||||||
ctx.ReplyForbidden()
|
ctx.ReplyForbidden()
|
||||||
|
|
||||||
|
|
|
@ -221,13 +221,10 @@ func handleOIDCWorkflowResponseWithID(ctx *middlewares.AutheliaCtx, id string) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if !client.IsAuthenticationLevelSufficient(userSession.AuthenticationLevel) {
|
policy := client.GetAuthorizationPolicy(authorization.Subject{Username: userSession.Username, Groups: userSession.Groups, IP: ctx.RemoteIP()})
|
||||||
ctx.Logger.Warnf("OpenID Connect client '%s' requires 2FA, cannot be redirected yet", client.GetID())
|
|
||||||
ctx.ReplyOK()
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case authorization.IsAuthLevelSufficient(userSession.AuthenticationLevel, policy), policy == authorization.Denied:
|
||||||
var (
|
var (
|
||||||
targetURL *url.URL
|
targetURL *url.URL
|
||||||
form url.Values
|
form url.Values
|
||||||
|
@ -249,6 +246,12 @@ func handleOIDCWorkflowResponseWithID(ctx *middlewares.AutheliaCtx, id string) {
|
||||||
if err = ctx.SetJSONBody(redirectResponse{Redirect: targetURL.String()}); err != nil {
|
if err = ctx.SetJSONBody(redirectResponse{Redirect: targetURL.String()}); err != nil {
|
||||||
ctx.Logger.Errorf("Unable to set default redirection URL in body: %s", err)
|
ctx.Logger.Errorf("Unable to set default redirection URL in body: %s", err)
|
||||||
}
|
}
|
||||||
|
default:
|
||||||
|
ctx.Logger.Warnf("OpenID Connect client '%s' requires 2FA, cannot be redirected yet", client.GetID())
|
||||||
|
ctx.ReplyOK()
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func markAuthenticationAttempt(ctx *middlewares.AutheliaCtx, successful bool, bannedUntil *time.Time, username string, authType string, errAuth error) (err error) {
|
func markAuthenticationAttempt(ctx *middlewares.AutheliaCtx, successful bool, bannedUntil *time.Time, username string, authType string, errAuth error) (err error) {
|
||||||
|
@ -277,18 +280,13 @@ func markAuthenticationAttempt(ctx *middlewares.AutheliaCtx, successful bool, ba
|
||||||
if successful {
|
if successful {
|
||||||
ctx.Logger.Debugf("Successful %s authentication attempt made by user '%s'", authType, username)
|
ctx.Logger.Debugf("Successful %s authentication attempt made by user '%s'", authType, username)
|
||||||
} else {
|
} else {
|
||||||
reasonPhrase := "by user '" + username + "'"
|
|
||||||
if ctx.Configuration.Server.UseIPInsteadOfUserForBan {
|
|
||||||
reasonPhrase = fmt.Sprintf("by ip %q (user %q)", ctx.RemoteIP().String(), username)
|
|
||||||
}
|
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
case errAuth != nil:
|
case errAuth != nil:
|
||||||
ctx.Logger.Errorf("Unsuccessful %s authentication attempt %s: %+v", authType, reasonPhrase, errAuth)
|
ctx.Logger.Errorf("Unsuccessful %s authentication attempt by user '%s': %+v", authType, username, errAuth)
|
||||||
case bannedUntil != nil:
|
case bannedUntil != nil:
|
||||||
ctx.Logger.Errorf("Unsuccessful %s authentication attempt %s and they are banned until %s", authType, reasonPhrase, bannedUntil)
|
ctx.Logger.Errorf("Unsuccessful %s authentication attempt by user '%s' and they are banned until %s", authType, username, bannedUntil)
|
||||||
default:
|
default:
|
||||||
ctx.Logger.Errorf("Unsuccessful %s authentication attempt %s", authType, reasonPhrase)
|
ctx.Logger.Errorf("Unsuccessful %s authentication attempt by user '%s'", authType, username)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -210,18 +210,18 @@ func (mr *MockStorageMockRecorder) FindIdentityVerification(arg0, arg1 interface
|
||||||
}
|
}
|
||||||
|
|
||||||
// LoadAuthenticationLogs mocks base method.
|
// LoadAuthenticationLogs mocks base method.
|
||||||
func (m *MockStorage) LoadAuthenticationLogs(arg0 context.Context, arg1, arg2 string, arg3 time.Time, arg4, arg5 int) ([]model.AuthenticationAttempt, error) {
|
func (m *MockStorage) LoadAuthenticationLogs(arg0 context.Context, arg1 string, arg2 time.Time, arg3, arg4 int) ([]model.AuthenticationAttempt, error) {
|
||||||
m.ctrl.T.Helper()
|
m.ctrl.T.Helper()
|
||||||
ret := m.ctrl.Call(m, "LoadAuthenticationLogs", arg0, arg1, arg2, arg3, arg4, arg5)
|
ret := m.ctrl.Call(m, "LoadAuthenticationLogs", arg0, arg1, arg2, arg3, arg4)
|
||||||
ret0, _ := ret[0].([]model.AuthenticationAttempt)
|
ret0, _ := ret[0].([]model.AuthenticationAttempt)
|
||||||
ret1, _ := ret[1].(error)
|
ret1, _ := ret[1].(error)
|
||||||
return ret0, ret1
|
return ret0, ret1
|
||||||
}
|
}
|
||||||
|
|
||||||
// LoadAuthenticationLogs indicates an expected call of LoadAuthenticationLogs.
|
// LoadAuthenticationLogs indicates an expected call of LoadAuthenticationLogs.
|
||||||
func (mr *MockStorageMockRecorder) LoadAuthenticationLogs(arg0, arg1, arg2, arg3, arg4, arg5 interface{}) *gomock.Call {
|
func (mr *MockStorageMockRecorder) LoadAuthenticationLogs(arg0, arg1, arg2, arg3, arg4 interface{}) *gomock.Call {
|
||||||
mr.mock.ctrl.T.Helper()
|
mr.mock.ctrl.T.Helper()
|
||||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LoadAuthenticationLogs", reflect.TypeOf((*MockStorage)(nil).LoadAuthenticationLogs), arg0, arg1, arg2, arg3, arg4, arg5)
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "LoadAuthenticationLogs", reflect.TypeOf((*MockStorage)(nil).LoadAuthenticationLogs), arg0, arg1, arg2, arg3, arg4)
|
||||||
}
|
}
|
||||||
|
|
||||||
// LoadOAuth2BlacklistedJTI mocks base method.
|
// LoadOAuth2BlacklistedJTI mocks base method.
|
||||||
|
|
|
@ -13,7 +13,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewClient creates a new Client.
|
// NewClient creates a new Client.
|
||||||
func NewClient(config schema.OpenIDConnectClient) (client Client) {
|
func NewClient(config schema.OpenIDConnectClient, c *schema.OpenIDConnect) (client Client) {
|
||||||
base := &BaseClient{
|
base := &BaseClient{
|
||||||
ID: config.ID,
|
ID: config.ID,
|
||||||
Description: config.Description,
|
Description: config.Description,
|
||||||
|
@ -39,8 +39,7 @@ func NewClient(config schema.OpenIDConnectClient) (client Client) {
|
||||||
UserinfoSigningAlg: config.UserinfoSigningAlg,
|
UserinfoSigningAlg: config.UserinfoSigningAlg,
|
||||||
UserinfoSigningKeyID: config.UserinfoSigningKeyID,
|
UserinfoSigningKeyID: config.UserinfoSigningKeyID,
|
||||||
|
|
||||||
Policy: authorization.NewLevel(config.Policy),
|
Policy: NewClientPolicy(config.Policy, c),
|
||||||
|
|
||||||
Consent: NewClientConsent(config.ConsentMode, config.ConsentPreConfiguredDuration),
|
Consent: NewClientConsent(config.ConsentMode, config.ConsentPreConfiguredDuration),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -192,9 +191,18 @@ func (c *BaseClient) GetPKCEChallengeMethod() string {
|
||||||
return c.PKCEChallengeMethod
|
return c.PKCEChallengeMethod
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IsAuthenticationLevelSufficient returns if the provided authentication.Level is sufficient for the client of the AutheliaClient.
|
||||||
|
func (c *BaseClient) IsAuthenticationLevelSufficient(level authentication.Level, subject authorization.Subject) bool {
|
||||||
|
if level == authentication.NotAuthenticated {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return authorization.IsAuthLevelSufficient(level, c.GetAuthorizationPolicy(subject))
|
||||||
|
}
|
||||||
|
|
||||||
// GetAuthorizationPolicy returns Policy.
|
// GetAuthorizationPolicy returns Policy.
|
||||||
func (c *BaseClient) GetAuthorizationPolicy() authorization.Level {
|
func (c *BaseClient) GetAuthorizationPolicy(subject authorization.Subject) authorization.Level {
|
||||||
return c.Policy
|
return c.Policy.GetRequiredLevel(subject)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetConsentPolicy returns Consent.
|
// GetConsentPolicy returns Consent.
|
||||||
|
@ -223,15 +231,6 @@ func (c *BaseClient) IsPublic() bool {
|
||||||
return c.Public
|
return c.Public
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsAuthenticationLevelSufficient returns if the provided authentication.Level is sufficient for the client of the AutheliaClient.
|
|
||||||
func (c *BaseClient) IsAuthenticationLevelSufficient(level authentication.Level) bool {
|
|
||||||
if level == authentication.NotAuthenticated {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
return authorization.IsAuthLevelSufficient(level, c.Policy)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ValidatePKCEPolicy is a helper function to validate PKCE policy constraints on a per-client basis.
|
// ValidatePKCEPolicy is a helper function to validate PKCE policy constraints on a per-client basis.
|
||||||
func (c *BaseClient) ValidatePKCEPolicy(r fosite.Requester) (err error) {
|
func (c *BaseClient) ValidatePKCEPolicy(r fosite.Requester) (err error) {
|
||||||
form := r.GetRequestForm()
|
form := r.GetRequestForm()
|
||||||
|
|
|
@ -0,0 +1,73 @@
|
||||||
|
package oidc
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/authelia/authelia/v4/internal/authorization"
|
||||||
|
"github.com/authelia/authelia/v4/internal/configuration/schema"
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewClientPolicy(name string, config *schema.OpenIDConnect) (policy ClientPolicy) {
|
||||||
|
switch name {
|
||||||
|
case authorization.OneFactor.String(), authorization.TwoFactor.String():
|
||||||
|
return ClientPolicy{DefaultPolicy: authorization.NewLevel(name)}
|
||||||
|
default:
|
||||||
|
if p, ok := config.Policies[name]; ok {
|
||||||
|
policy.DefaultPolicy = authorization.NewLevel(p.DefaultPolicy)
|
||||||
|
|
||||||
|
for _, r := range p.Rules {
|
||||||
|
policy.Rules = append(policy.Rules, ClientPolicyRule{
|
||||||
|
Policy: authorization.NewLevel(r.Policy),
|
||||||
|
Subjects: authorization.NewSubjects(r.Subjects),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return policy
|
||||||
|
}
|
||||||
|
|
||||||
|
return ClientPolicy{DefaultPolicy: authorization.TwoFactor}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ClientPolicy controls and represents a client policy.
|
||||||
|
type ClientPolicy struct {
|
||||||
|
DefaultPolicy authorization.Level
|
||||||
|
Rules []ClientPolicyRule
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *ClientPolicy) GetRequiredLevel(subject authorization.Subject) authorization.Level {
|
||||||
|
for _, rule := range p.Rules {
|
||||||
|
if rule.IsMatch(subject) {
|
||||||
|
return rule.Policy
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return p.DefaultPolicy
|
||||||
|
}
|
||||||
|
|
||||||
|
type ClientPolicyRule struct {
|
||||||
|
Subjects []authorization.AccessControlSubjects
|
||||||
|
Policy authorization.Level
|
||||||
|
}
|
||||||
|
|
||||||
|
// MatchesSubjects returns true if the rule matches the subjects.
|
||||||
|
func (p *ClientPolicyRule) MatchesSubjects(subject authorization.Subject) (match bool) {
|
||||||
|
// If there are no subjects in this rule then the subject condition is a match.
|
||||||
|
if len(p.Subjects) == 0 {
|
||||||
|
return true
|
||||||
|
} else if subject.IsAnonymous() {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Iterate over the subjects until we find a match (return true) or until we exit the loop (return false).
|
||||||
|
for _, rule := range p.Subjects {
|
||||||
|
if rule.IsMatch(subject) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsMatch returns true if all elements of an AccessControlRule match the object and subject.
|
||||||
|
func (p *ClientPolicyRule) IsMatch(subject authorization.Subject) (match bool) {
|
||||||
|
return p.MatchesSubjects(subject)
|
||||||
|
}
|
|
@ -19,7 +19,7 @@ import (
|
||||||
|
|
||||||
func TestNewClient(t *testing.T) {
|
func TestNewClient(t *testing.T) {
|
||||||
config := schema.OpenIDConnectClient{}
|
config := schema.OpenIDConnectClient{}
|
||||||
client := oidc.NewClient(config)
|
client := oidc.NewClient(config, &schema.OpenIDConnect{})
|
||||||
assert.Equal(t, "", client.GetID())
|
assert.Equal(t, "", client.GetID())
|
||||||
assert.Equal(t, "", client.GetDescription())
|
assert.Equal(t, "", client.GetDescription())
|
||||||
assert.Len(t, client.GetResponseModes(), 0)
|
assert.Len(t, client.GetResponseModes(), 0)
|
||||||
|
@ -47,17 +47,17 @@ func TestNewClient(t *testing.T) {
|
||||||
ResponseModes: schema.DefaultOpenIDConnectClientConfiguration.ResponseModes,
|
ResponseModes: schema.DefaultOpenIDConnectClientConfiguration.ResponseModes,
|
||||||
}
|
}
|
||||||
|
|
||||||
client = oidc.NewClient(config)
|
client = oidc.NewClient(config, &schema.OpenIDConnect{})
|
||||||
assert.Equal(t, myclient, client.GetID())
|
assert.Equal(t, myclient, client.GetID())
|
||||||
require.Len(t, client.GetResponseModes(), 1)
|
require.Len(t, client.GetResponseModes(), 1)
|
||||||
assert.Equal(t, fosite.ResponseModeFormPost, client.GetResponseModes()[0])
|
assert.Equal(t, fosite.ResponseModeFormPost, client.GetResponseModes()[0])
|
||||||
assert.Equal(t, authorization.TwoFactor, client.GetAuthorizationPolicy())
|
assert.Equal(t, authorization.TwoFactor, client.GetAuthorizationPolicy(authorization.Subject{}))
|
||||||
|
|
||||||
config = schema.OpenIDConnectClient{
|
config = schema.OpenIDConnectClient{
|
||||||
TokenEndpointAuthMethod: oidc.ClientAuthMethodClientSecretPost,
|
TokenEndpointAuthMethod: oidc.ClientAuthMethodClientSecretPost,
|
||||||
}
|
}
|
||||||
|
|
||||||
client = oidc.NewClient(config)
|
client = oidc.NewClient(config, &schema.OpenIDConnect{})
|
||||||
|
|
||||||
fclient, ok := client.(*oidc.FullClient)
|
fclient, ok := client.(*oidc.FullClient)
|
||||||
|
|
||||||
|
@ -204,25 +204,25 @@ func TestBaseClient_ValidatePARPolicy(t *testing.T) {
|
||||||
func TestIsAuthenticationLevelSufficient(t *testing.T) {
|
func TestIsAuthenticationLevelSufficient(t *testing.T) {
|
||||||
c := &oidc.FullClient{BaseClient: &oidc.BaseClient{}}
|
c := &oidc.FullClient{BaseClient: &oidc.BaseClient{}}
|
||||||
|
|
||||||
c.Policy = authorization.Bypass
|
c.Policy = oidc.ClientPolicy{DefaultPolicy: authorization.Bypass}
|
||||||
assert.False(t, c.IsAuthenticationLevelSufficient(authentication.NotAuthenticated))
|
assert.False(t, c.IsAuthenticationLevelSufficient(authentication.NotAuthenticated, authorization.Subject{}))
|
||||||
assert.True(t, c.IsAuthenticationLevelSufficient(authentication.OneFactor))
|
assert.True(t, c.IsAuthenticationLevelSufficient(authentication.OneFactor, authorization.Subject{}))
|
||||||
assert.True(t, c.IsAuthenticationLevelSufficient(authentication.TwoFactor))
|
assert.True(t, c.IsAuthenticationLevelSufficient(authentication.TwoFactor, authorization.Subject{}))
|
||||||
|
|
||||||
c.Policy = authorization.OneFactor
|
c.Policy = oidc.ClientPolicy{DefaultPolicy: authorization.OneFactor}
|
||||||
assert.False(t, c.IsAuthenticationLevelSufficient(authentication.NotAuthenticated))
|
assert.False(t, c.IsAuthenticationLevelSufficient(authentication.NotAuthenticated, authorization.Subject{}))
|
||||||
assert.True(t, c.IsAuthenticationLevelSufficient(authentication.OneFactor))
|
assert.True(t, c.IsAuthenticationLevelSufficient(authentication.OneFactor, authorization.Subject{}))
|
||||||
assert.True(t, c.IsAuthenticationLevelSufficient(authentication.TwoFactor))
|
assert.True(t, c.IsAuthenticationLevelSufficient(authentication.TwoFactor, authorization.Subject{}))
|
||||||
|
|
||||||
c.Policy = authorization.TwoFactor
|
c.Policy = oidc.ClientPolicy{DefaultPolicy: authorization.TwoFactor}
|
||||||
assert.False(t, c.IsAuthenticationLevelSufficient(authentication.NotAuthenticated))
|
assert.False(t, c.IsAuthenticationLevelSufficient(authentication.NotAuthenticated, authorization.Subject{}))
|
||||||
assert.False(t, c.IsAuthenticationLevelSufficient(authentication.OneFactor))
|
assert.False(t, c.IsAuthenticationLevelSufficient(authentication.OneFactor, authorization.Subject{}))
|
||||||
assert.True(t, c.IsAuthenticationLevelSufficient(authentication.TwoFactor))
|
assert.True(t, c.IsAuthenticationLevelSufficient(authentication.TwoFactor, authorization.Subject{}))
|
||||||
|
|
||||||
c.Policy = authorization.Denied
|
c.Policy = oidc.ClientPolicy{DefaultPolicy: authorization.Denied}
|
||||||
assert.False(t, c.IsAuthenticationLevelSufficient(authentication.NotAuthenticated))
|
assert.False(t, c.IsAuthenticationLevelSufficient(authentication.NotAuthenticated, authorization.Subject{}))
|
||||||
assert.False(t, c.IsAuthenticationLevelSufficient(authentication.OneFactor))
|
assert.False(t, c.IsAuthenticationLevelSufficient(authentication.OneFactor, authorization.Subject{}))
|
||||||
assert.False(t, c.IsAuthenticationLevelSufficient(authentication.TwoFactor))
|
assert.False(t, c.IsAuthenticationLevelSufficient(authentication.TwoFactor, authorization.Subject{}))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestClient_GetConsentResponseBody(t *testing.T) {
|
func TestClient_GetConsentResponseBody(t *testing.T) {
|
||||||
|
@ -446,7 +446,7 @@ func TestNewClientPKCE(t *testing.T) {
|
||||||
|
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
t.Run(tc.name, func(t *testing.T) {
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
client := oidc.NewClient(tc.have)
|
client := oidc.NewClient(tc.have, &schema.OpenIDConnect{})
|
||||||
|
|
||||||
assert.Equal(t, tc.expectedEnforcePKCE, client.GetPKCEEnforcement())
|
assert.Equal(t, tc.expectedEnforcePKCE, client.GetPKCEEnforcement())
|
||||||
assert.Equal(t, tc.expectedEnforcePKCEChallengeMethod, client.GetPKCEChallengeMethodEnforcement())
|
assert.Equal(t, tc.expectedEnforcePKCEChallengeMethod, client.GetPKCEChallengeMethodEnforcement())
|
||||||
|
@ -511,7 +511,7 @@ func TestNewClientPAR(t *testing.T) {
|
||||||
|
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
t.Run(tc.name, func(t *testing.T) {
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
client := oidc.NewClient(tc.have)
|
client := oidc.NewClient(tc.have, &schema.OpenIDConnect{})
|
||||||
|
|
||||||
assert.Equal(t, tc.expected, client.GetPAREnforcement())
|
assert.Equal(t, tc.expected, client.GetPAREnforcement())
|
||||||
|
|
||||||
|
@ -575,7 +575,7 @@ func TestNewClientResponseModes(t *testing.T) {
|
||||||
|
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
t.Run(tc.name, func(t *testing.T) {
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
client := oidc.NewClient(tc.have)
|
client := oidc.NewClient(tc.have, &schema.OpenIDConnect{})
|
||||||
|
|
||||||
assert.Equal(t, tc.expected, client.GetResponseModes())
|
assert.Equal(t, tc.expected, client.GetResponseModes())
|
||||||
|
|
||||||
|
@ -615,7 +615,7 @@ func TestNewClient_JSONWebKeySetURI(t *testing.T) {
|
||||||
PublicKeys: schema.OpenIDConnectClientPublicKeys{
|
PublicKeys: schema.OpenIDConnectClientPublicKeys{
|
||||||
URI: MustParseRequestURI("https://google.com"),
|
URI: MustParseRequestURI("https://google.com"),
|
||||||
},
|
},
|
||||||
})
|
}, &schema.OpenIDConnect{})
|
||||||
|
|
||||||
require.NotNil(t, client)
|
require.NotNil(t, client)
|
||||||
|
|
||||||
|
@ -630,7 +630,7 @@ func TestNewClient_JSONWebKeySetURI(t *testing.T) {
|
||||||
PublicKeys: schema.OpenIDConnectClientPublicKeys{
|
PublicKeys: schema.OpenIDConnectClientPublicKeys{
|
||||||
URI: nil,
|
URI: nil,
|
||||||
},
|
},
|
||||||
})
|
}, &schema.OpenIDConnect{})
|
||||||
|
|
||||||
require.NotNil(t, client)
|
require.NotNil(t, client)
|
||||||
|
|
||||||
|
|
|
@ -32,4 +32,6 @@ var (
|
||||||
|
|
||||||
// ErrPAREnforcedClientMissingPAR is sent when a client has EnforcePAR configured but the Authorization Request was not Pushed.
|
// ErrPAREnforcedClientMissingPAR is sent when a client has EnforcePAR configured but the Authorization Request was not Pushed.
|
||||||
ErrPAREnforcedClientMissingPAR = fosite.ErrInvalidRequest.WithHint("Pushed Authorization Requests are enforced for this client but no such request was sent.")
|
ErrPAREnforcedClientMissingPAR = fosite.ErrInvalidRequest.WithHint("Pushed Authorization Requests are enforced for this client but no such request was sent.")
|
||||||
|
|
||||||
|
ErrClientAuthorizationUserAccessDenied = fosite.ErrAccessDenied.WithHint("The user was denied access to this client.")
|
||||||
)
|
)
|
||||||
|
|
|
@ -31,7 +31,7 @@ func NewStore(config *schema.OpenIDConnect, provider storage.Provider) (store *S
|
||||||
policy := authorization.NewLevel(client.Policy)
|
policy := authorization.NewLevel(client.Policy)
|
||||||
logger.Debugf("Registering client %s with policy %s (%v)", client.ID, client.Policy, policy)
|
logger.Debugf("Registering client %s with policy %s (%v)", client.ID, client.Policy, policy)
|
||||||
|
|
||||||
store.clients[client.ID] = NewClient(client)
|
store.clients[client.ID] = NewClient(client, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
return store
|
return store
|
||||||
|
@ -65,16 +65,6 @@ func (s *Store) GetSubject(ctx context.Context, sectorID, username string) (subj
|
||||||
return opaqueID.Identifier, nil
|
return opaqueID.Identifier, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetClientPolicy retrieves the policy from the client with the matching provided id.
|
|
||||||
func (s *Store) GetClientPolicy(id string) (level authorization.Level) {
|
|
||||||
client, err := s.GetFullClient(id)
|
|
||||||
if err != nil {
|
|
||||||
return authorization.TwoFactor
|
|
||||||
}
|
|
||||||
|
|
||||||
return client.GetAuthorizationPolicy()
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetFullClient returns a fosite.Client asserted as an Client matching the provided id.
|
// GetFullClient returns a fosite.Client asserted as an Client matching the provided id.
|
||||||
func (s *Store) GetFullClient(id string) (client Client, err error) {
|
func (s *Store) GetFullClient(id string) (client Client, err error) {
|
||||||
client, ok := s.clients[id]
|
client, ok := s.clients[id]
|
||||||
|
|
|
@ -23,38 +23,6 @@ import (
|
||||||
"github.com/authelia/authelia/v4/internal/storage"
|
"github.com/authelia/authelia/v4/internal/storage"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestOpenIDConnectStore_GetClientPolicy(t *testing.T) {
|
|
||||||
s := oidc.NewStore(&schema.OpenIDConnect{
|
|
||||||
IssuerCertificateChain: schema.X509CertificateChain{},
|
|
||||||
IssuerPrivateKey: keyRSA2048,
|
|
||||||
Clients: []schema.OpenIDConnectClient{
|
|
||||||
{
|
|
||||||
ID: myclient,
|
|
||||||
Description: myclientdesc,
|
|
||||||
Policy: onefactor,
|
|
||||||
Scopes: []string{oidc.ScopeOpenID, oidc.ScopeProfile},
|
|
||||||
Secret: tOpenIDConnectPlainTextClientSecret,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
ID: "myotherclient",
|
|
||||||
Description: myclientdesc,
|
|
||||||
Policy: twofactor,
|
|
||||||
Scopes: []string{oidc.ScopeOpenID, oidc.ScopeProfile},
|
|
||||||
Secret: tOpenIDConnectPlainTextClientSecret,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}, nil)
|
|
||||||
|
|
||||||
policyOne := s.GetClientPolicy(myclient)
|
|
||||||
assert.Equal(t, authorization.OneFactor, policyOne)
|
|
||||||
|
|
||||||
policyTwo := s.GetClientPolicy("myotherclient")
|
|
||||||
assert.Equal(t, authorization.TwoFactor, policyTwo)
|
|
||||||
|
|
||||||
policyInvalid := s.GetClientPolicy("invalidclient")
|
|
||||||
assert.Equal(t, authorization.TwoFactor, policyInvalid)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestOpenIDConnectStore_GetInternalClient(t *testing.T) {
|
func TestOpenIDConnectStore_GetInternalClient(t *testing.T) {
|
||||||
s := oidc.NewStore(&schema.OpenIDConnect{
|
s := oidc.NewStore(&schema.OpenIDConnect{
|
||||||
IssuerCertificateChain: schema.X509CertificateChain{},
|
IssuerCertificateChain: schema.X509CertificateChain{},
|
||||||
|
@ -106,7 +74,7 @@ func TestOpenIDConnectStore_GetInternalClient_ValidClient(t *testing.T) {
|
||||||
assert.Equal(t, fosite.Arguments([]string{oidc.GrantTypeAuthorizationCode}), client.GetGrantTypes())
|
assert.Equal(t, fosite.Arguments([]string{oidc.GrantTypeAuthorizationCode}), client.GetGrantTypes())
|
||||||
assert.Equal(t, fosite.Arguments([]string{oidc.ResponseTypeAuthorizationCodeFlow}), client.GetResponseTypes())
|
assert.Equal(t, fosite.Arguments([]string{oidc.ResponseTypeAuthorizationCodeFlow}), client.GetResponseTypes())
|
||||||
assert.Equal(t, []string(nil), client.GetRedirectURIs())
|
assert.Equal(t, []string(nil), client.GetRedirectURIs())
|
||||||
assert.Equal(t, authorization.OneFactor, client.GetAuthorizationPolicy())
|
assert.Equal(t, authorization.OneFactor, client.GetAuthorizationPolicy(authorization.Subject{}))
|
||||||
assert.Equal(t, "$plaintext$client-secret", client.GetSecret().Encode())
|
assert.Equal(t, "$plaintext$client-secret", client.GetSecret().Encode())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@ import (
|
||||||
"github.com/ory/fosite/handler/openid"
|
"github.com/ory/fosite/handler/openid"
|
||||||
"github.com/ory/fosite/token/jwt"
|
"github.com/ory/fosite/token/jwt"
|
||||||
"github.com/ory/herodot"
|
"github.com/ory/herodot"
|
||||||
"gopkg.in/square/go-jose.v2"
|
jose "gopkg.in/square/go-jose.v2"
|
||||||
|
|
||||||
"github.com/authelia/authelia/v4/internal/authentication"
|
"github.com/authelia/authelia/v4/internal/authentication"
|
||||||
"github.com/authelia/authelia/v4/internal/authorization"
|
"github.com/authelia/authelia/v4/internal/authorization"
|
||||||
|
@ -127,7 +127,7 @@ type BaseClient struct {
|
||||||
UserinfoSigningAlg string
|
UserinfoSigningAlg string
|
||||||
UserinfoSigningKeyID string
|
UserinfoSigningKeyID string
|
||||||
|
|
||||||
Policy authorization.Level
|
Policy ClientPolicy
|
||||||
|
|
||||||
Consent ClientConsent
|
Consent ClientConsent
|
||||||
}
|
}
|
||||||
|
@ -164,14 +164,14 @@ type Client interface {
|
||||||
GetPKCEEnforcement() bool
|
GetPKCEEnforcement() bool
|
||||||
GetPKCEChallengeMethodEnforcement() bool
|
GetPKCEChallengeMethodEnforcement() bool
|
||||||
GetPKCEChallengeMethod() string
|
GetPKCEChallengeMethod() string
|
||||||
GetAuthorizationPolicy() authorization.Level
|
|
||||||
GetConsentPolicy() ClientConsent
|
|
||||||
|
|
||||||
IsAuthenticationLevelSufficient(level authentication.Level) bool
|
|
||||||
|
|
||||||
ValidatePKCEPolicy(r fosite.Requester) (err error)
|
ValidatePKCEPolicy(r fosite.Requester) (err error)
|
||||||
ValidatePARPolicy(r fosite.Requester, prefix string) (err error)
|
ValidatePARPolicy(r fosite.Requester, prefix string) (err error)
|
||||||
ValidateResponseModePolicy(r fosite.AuthorizeRequester) (err error)
|
ValidateResponseModePolicy(r fosite.AuthorizeRequester) (err error)
|
||||||
|
|
||||||
|
GetConsentPolicy() ClientConsent
|
||||||
|
IsAuthenticationLevelSufficient(level authentication.Level, subject authorization.Subject) bool
|
||||||
|
GetAuthorizationPolicy(subject authorization.Subject) authorization.Level
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewClientConsent converts the schema.OpenIDConnectClientConsentConfig into a oidc.ClientConsent.
|
// NewClientConsent converts the schema.OpenIDConnectClientConsentConfig into a oidc.ClientConsent.
|
||||||
|
|
|
@ -40,13 +40,13 @@ func (r *Regulator) Mark(ctx Context, successful, banned bool, username, request
|
||||||
|
|
||||||
// Regulate the authentication attempts for a given user.
|
// Regulate the authentication attempts for a given user.
|
||||||
// This method returns ErrUserIsBanned if the user is banned along with the time until when the user is banned.
|
// This method returns ErrUserIsBanned if the user is banned along with the time until when the user is banned.
|
||||||
func (r *Regulator) Regulate(ctx context.Context, username string, remoteIp string) (time.Time, error) {
|
func (r *Regulator) Regulate(ctx context.Context, username string) (time.Time, error) {
|
||||||
// If there is regulation configuration, no regulation applies.
|
// If there is regulation configuration, no regulation applies.
|
||||||
if !r.enabled {
|
if !r.enabled {
|
||||||
return time.Time{}, nil
|
return time.Time{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
attempts, err := r.store.LoadAuthenticationLogs(ctx, username, remoteIp, r.clock.Now().Add(-r.config.BanTime), 10, 0)
|
attempts, err := r.store.LoadAuthenticationLogs(ctx, username, r.clock.Now().Add(-r.config.BanTime), 10, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return time.Time{}, nil
|
return time.Time{}, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,8 +23,6 @@ type RegulatorSuite struct {
|
||||||
mock *mocks.MockAutheliaCtx
|
mock *mocks.MockAutheliaCtx
|
||||||
}
|
}
|
||||||
|
|
||||||
// @TODO
|
|
||||||
// Extend this test for IP ban :)
|
|
||||||
func (s *RegulatorSuite) SetupTest() {
|
func (s *RegulatorSuite) SetupTest() {
|
||||||
s.mock = mocks.NewMockAutheliaCtx(s.T())
|
s.mock = mocks.NewMockAutheliaCtx(s.T())
|
||||||
s.mock.Ctx.Configuration.Regulation = schema.RegulationConfiguration{
|
s.mock.Ctx.Configuration.Regulation = schema.RegulationConfiguration{
|
||||||
|
@ -60,9 +58,9 @@ func (s *RegulatorSuite) TestShouldMark() {
|
||||||
func (s *RegulatorSuite) TestShouldHandleRegulateError() {
|
func (s *RegulatorSuite) TestShouldHandleRegulateError() {
|
||||||
regulator := regulation.NewRegulator(s.mock.Ctx.Configuration.Regulation, s.mock.StorageMock, &s.mock.Clock)
|
regulator := regulation.NewRegulator(s.mock.Ctx.Configuration.Regulation, s.mock.StorageMock, &s.mock.Clock)
|
||||||
|
|
||||||
s.mock.StorageMock.EXPECT().LoadAuthenticationLogs(s.mock.Ctx, "john", "127.0.0.1", s.mock.Clock.Now().Add(-s.mock.Ctx.Configuration.Regulation.BanTime), 10, 0).Return(nil, fmt.Errorf("failed"))
|
s.mock.StorageMock.EXPECT().LoadAuthenticationLogs(s.mock.Ctx, "john", s.mock.Clock.Now().Add(-s.mock.Ctx.Configuration.Regulation.BanTime), 10, 0).Return(nil, fmt.Errorf("failed"))
|
||||||
|
|
||||||
until, err := regulator.Regulate(s.mock.Ctx, "john", "127.0.0.1")
|
until, err := regulator.Regulate(s.mock.Ctx, "john")
|
||||||
|
|
||||||
s.NoError(err)
|
s.NoError(err)
|
||||||
s.Equal(time.Time{}, until)
|
s.Equal(time.Time{}, until)
|
||||||
|
@ -78,12 +76,12 @@ func (s *RegulatorSuite) TestShouldNotThrowWhenUserIsLegitimate() {
|
||||||
}
|
}
|
||||||
|
|
||||||
s.mock.StorageMock.EXPECT().
|
s.mock.StorageMock.EXPECT().
|
||||||
LoadAuthenticationLogs(s.mock.Ctx, gomock.Eq("john"), "127.0.0.1", gomock.Any(), gomock.Eq(10), gomock.Eq(0)).
|
LoadAuthenticationLogs(s.mock.Ctx, gomock.Eq("john"), gomock.Any(), gomock.Eq(10), gomock.Eq(0)).
|
||||||
Return(attemptsInDB, nil)
|
Return(attemptsInDB, nil)
|
||||||
|
|
||||||
regulator := regulation.NewRegulator(s.mock.Ctx.Configuration.Regulation, s.mock.StorageMock, &s.mock.Clock)
|
regulator := regulation.NewRegulator(s.mock.Ctx.Configuration.Regulation, s.mock.StorageMock, &s.mock.Clock)
|
||||||
|
|
||||||
_, err := regulator.Regulate(s.mock.Ctx, "john", "127.0.0.1")
|
_, err := regulator.Regulate(s.mock.Ctx, "john")
|
||||||
assert.NoError(s.T(), err)
|
assert.NoError(s.T(), err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -109,12 +107,12 @@ func (s *RegulatorSuite) TestShouldNotThrowWhenFailedAuthenticationNotInFindTime
|
||||||
}
|
}
|
||||||
|
|
||||||
s.mock.StorageMock.EXPECT().
|
s.mock.StorageMock.EXPECT().
|
||||||
LoadAuthenticationLogs(s.mock.Ctx, gomock.Eq("john"), "127.0.0.1", gomock.Any(), gomock.Eq(10), gomock.Eq(0)).
|
LoadAuthenticationLogs(s.mock.Ctx, gomock.Eq("john"), gomock.Any(), gomock.Eq(10), gomock.Eq(0)).
|
||||||
Return(attemptsInDB, nil)
|
Return(attemptsInDB, nil)
|
||||||
|
|
||||||
regulator := regulation.NewRegulator(s.mock.Ctx.Configuration.Regulation, s.mock.StorageMock, &s.mock.Clock)
|
regulator := regulation.NewRegulator(s.mock.Ctx.Configuration.Regulation, s.mock.StorageMock, &s.mock.Clock)
|
||||||
|
|
||||||
_, err := regulator.Regulate(s.mock.Ctx, "john", "127.0.0.1")
|
_, err := regulator.Regulate(s.mock.Ctx, "john")
|
||||||
assert.NoError(s.T(), err)
|
assert.NoError(s.T(), err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -145,12 +143,12 @@ func (s *RegulatorSuite) TestShouldBanUserIfLatestAttemptsAreWithinFinTime() {
|
||||||
}
|
}
|
||||||
|
|
||||||
s.mock.StorageMock.EXPECT().
|
s.mock.StorageMock.EXPECT().
|
||||||
LoadAuthenticationLogs(s.mock.Ctx, gomock.Eq("john"), "127.0.0.1", gomock.Any(), gomock.Eq(10), gomock.Eq(0)).
|
LoadAuthenticationLogs(s.mock.Ctx, gomock.Eq("john"), gomock.Any(), gomock.Eq(10), gomock.Eq(0)).
|
||||||
Return(attemptsInDB, nil)
|
Return(attemptsInDB, nil)
|
||||||
|
|
||||||
regulator := regulation.NewRegulator(s.mock.Ctx.Configuration.Regulation, s.mock.StorageMock, &s.mock.Clock)
|
regulator := regulation.NewRegulator(s.mock.Ctx.Configuration.Regulation, s.mock.StorageMock, &s.mock.Clock)
|
||||||
|
|
||||||
_, err := regulator.Regulate(s.mock.Ctx, "john", "127.0.0.1")
|
_, err := regulator.Regulate(s.mock.Ctx, "john")
|
||||||
assert.Equal(s.T(), regulation.ErrUserIsBanned, err)
|
assert.Equal(s.T(), regulation.ErrUserIsBanned, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -178,12 +176,12 @@ func (s *RegulatorSuite) TestShouldCheckUserIsStillBanned() {
|
||||||
}
|
}
|
||||||
|
|
||||||
s.mock.StorageMock.EXPECT().
|
s.mock.StorageMock.EXPECT().
|
||||||
LoadAuthenticationLogs(s.mock.Ctx, gomock.Eq("john"), "127.0.0.1", gomock.Any(), gomock.Eq(10), gomock.Eq(0)).
|
LoadAuthenticationLogs(s.mock.Ctx, gomock.Eq("john"), gomock.Any(), gomock.Eq(10), gomock.Eq(0)).
|
||||||
Return(attemptsInDB, nil)
|
Return(attemptsInDB, nil)
|
||||||
|
|
||||||
regulator := regulation.NewRegulator(s.mock.Ctx.Configuration.Regulation, s.mock.StorageMock, &s.mock.Clock)
|
regulator := regulation.NewRegulator(s.mock.Ctx.Configuration.Regulation, s.mock.StorageMock, &s.mock.Clock)
|
||||||
|
|
||||||
_, err := regulator.Regulate(s.mock.Ctx, "john", "127.0.0.1")
|
_, err := regulator.Regulate(s.mock.Ctx, "john")
|
||||||
assert.Equal(s.T(), regulation.ErrUserIsBanned, err)
|
assert.Equal(s.T(), regulation.ErrUserIsBanned, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -202,12 +200,12 @@ func (s *RegulatorSuite) TestShouldCheckUserIsNotYetBanned() {
|
||||||
}
|
}
|
||||||
|
|
||||||
s.mock.StorageMock.EXPECT().
|
s.mock.StorageMock.EXPECT().
|
||||||
LoadAuthenticationLogs(s.mock.Ctx, gomock.Eq("john"), "127.0.0.1", gomock.Any(), gomock.Eq(10), gomock.Eq(0)).
|
LoadAuthenticationLogs(s.mock.Ctx, gomock.Eq("john"), gomock.Any(), gomock.Eq(10), gomock.Eq(0)).
|
||||||
Return(attemptsInDB, nil)
|
Return(attemptsInDB, nil)
|
||||||
|
|
||||||
regulator := regulation.NewRegulator(s.mock.Ctx.Configuration.Regulation, s.mock.StorageMock, &s.mock.Clock)
|
regulator := regulation.NewRegulator(s.mock.Ctx.Configuration.Regulation, s.mock.StorageMock, &s.mock.Clock)
|
||||||
|
|
||||||
_, err := regulator.Regulate(s.mock.Ctx, "john", "127.0.0.1")
|
_, err := regulator.Regulate(s.mock.Ctx, "john")
|
||||||
assert.NoError(s.T(), err)
|
assert.NoError(s.T(), err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -234,12 +232,12 @@ func (s *RegulatorSuite) TestShouldCheckUserWasAboutToBeBanned() {
|
||||||
}
|
}
|
||||||
|
|
||||||
s.mock.StorageMock.EXPECT().
|
s.mock.StorageMock.EXPECT().
|
||||||
LoadAuthenticationLogs(s.mock.Ctx, gomock.Eq("john"), "127.0.0.1", gomock.Any(), gomock.Eq(10), gomock.Eq(0)).
|
LoadAuthenticationLogs(s.mock.Ctx, gomock.Eq("john"), gomock.Any(), gomock.Eq(10), gomock.Eq(0)).
|
||||||
Return(attemptsInDB, nil)
|
Return(attemptsInDB, nil)
|
||||||
|
|
||||||
regulator := regulation.NewRegulator(s.mock.Ctx.Configuration.Regulation, s.mock.StorageMock, &s.mock.Clock)
|
regulator := regulation.NewRegulator(s.mock.Ctx.Configuration.Regulation, s.mock.StorageMock, &s.mock.Clock)
|
||||||
|
|
||||||
_, err := regulator.Regulate(s.mock.Ctx, "john", "127.0.0.1")
|
_, err := regulator.Regulate(s.mock.Ctx, "john")
|
||||||
assert.NoError(s.T(), err)
|
assert.NoError(s.T(), err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -270,12 +268,12 @@ func (s *RegulatorSuite) TestShouldCheckRegulationHasBeenResetOnSuccessfulAttemp
|
||||||
}
|
}
|
||||||
|
|
||||||
s.mock.StorageMock.EXPECT().
|
s.mock.StorageMock.EXPECT().
|
||||||
LoadAuthenticationLogs(s.mock.Ctx, gomock.Eq("john"), "127.0.0.1", gomock.Any(), gomock.Eq(10), gomock.Eq(0)).
|
LoadAuthenticationLogs(s.mock.Ctx, gomock.Eq("john"), gomock.Any(), gomock.Eq(10), gomock.Eq(0)).
|
||||||
Return(attemptsInDB, nil)
|
Return(attemptsInDB, nil)
|
||||||
|
|
||||||
regulator := regulation.NewRegulator(s.mock.Ctx.Configuration.Regulation, s.mock.StorageMock, &s.mock.Clock)
|
regulator := regulation.NewRegulator(s.mock.Ctx.Configuration.Regulation, s.mock.StorageMock, &s.mock.Clock)
|
||||||
|
|
||||||
_, err := regulator.Regulate(s.mock.Ctx, "john", "127.0.0.1")
|
_, err := regulator.Regulate(s.mock.Ctx, "john")
|
||||||
assert.NoError(s.T(), err)
|
assert.NoError(s.T(), err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -305,7 +303,7 @@ func (s *RegulatorSuite) TestShouldHaveRegulatorDisabled() {
|
||||||
}
|
}
|
||||||
|
|
||||||
s.mock.StorageMock.EXPECT().
|
s.mock.StorageMock.EXPECT().
|
||||||
LoadAuthenticationLogs(s.mock.Ctx, gomock.Eq("john"), "127.0.0.1", gomock.Any(), gomock.Eq(10), gomock.Eq(0)).
|
LoadAuthenticationLogs(s.mock.Ctx, gomock.Eq("john"), gomock.Any(), gomock.Eq(10), gomock.Eq(0)).
|
||||||
Return(attemptsInDB, nil)
|
Return(attemptsInDB, nil)
|
||||||
|
|
||||||
// Check Disabled Functionality.
|
// Check Disabled Functionality.
|
||||||
|
@ -316,7 +314,7 @@ func (s *RegulatorSuite) TestShouldHaveRegulatorDisabled() {
|
||||||
}
|
}
|
||||||
|
|
||||||
regulator := regulation.NewRegulator(config, s.mock.StorageMock, &s.mock.Clock)
|
regulator := regulation.NewRegulator(config, s.mock.StorageMock, &s.mock.Clock)
|
||||||
_, err := regulator.Regulate(s.mock.Ctx, "john", "127.0.0.1")
|
_, err := regulator.Regulate(s.mock.Ctx, "john")
|
||||||
assert.NoError(s.T(), err)
|
assert.NoError(s.T(), err)
|
||||||
|
|
||||||
// Check Enabled Functionality.
|
// Check Enabled Functionality.
|
||||||
|
@ -327,6 +325,6 @@ func (s *RegulatorSuite) TestShouldHaveRegulatorDisabled() {
|
||||||
}
|
}
|
||||||
|
|
||||||
regulator = regulation.NewRegulator(config, s.mock.StorageMock, &s.mock.Clock)
|
regulator = regulation.NewRegulator(config, s.mock.StorageMock, &s.mock.Clock)
|
||||||
_, err = regulator.Regulate(s.mock.Ctx, "john", "127.0.0.1")
|
_, err = regulator.Regulate(s.mock.Ctx, "john")
|
||||||
assert.Equal(s.T(), regulation.ErrUserIsBanned, err)
|
assert.Equal(s.T(), regulation.ErrUserIsBanned, err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,6 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
duoapi "github.com/duosecurity/duo_api_golang"
|
duoapi "github.com/duosecurity/duo_api_golang"
|
||||||
autha "github.com/envoyproxy/go-control-plane/envoy/service/auth/v3"
|
|
||||||
"github.com/fasthttp/router"
|
"github.com/fasthttp/router"
|
||||||
"github.com/prometheus/client_golang/prometheus/promhttp"
|
"github.com/prometheus/client_golang/prometheus/promhttp"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
|
@ -17,8 +16,6 @@ import (
|
||||||
"github.com/valyala/fasthttp/expvarhandler"
|
"github.com/valyala/fasthttp/expvarhandler"
|
||||||
"github.com/valyala/fasthttp/fasthttpadaptor"
|
"github.com/valyala/fasthttp/fasthttpadaptor"
|
||||||
"github.com/valyala/fasthttp/pprofhandler"
|
"github.com/valyala/fasthttp/pprofhandler"
|
||||||
"google.golang.org/grpc"
|
|
||||||
healthpb "google.golang.org/grpc/health/grpc_health_v1"
|
|
||||||
|
|
||||||
"github.com/authelia/authelia/v4/internal/configuration/schema"
|
"github.com/authelia/authelia/v4/internal/configuration/schema"
|
||||||
"github.com/authelia/authelia/v4/internal/duo"
|
"github.com/authelia/authelia/v4/internal/duo"
|
||||||
|
@ -192,7 +189,7 @@ func handleRouter(config *schema.Configuration, providers middlewares.Providers)
|
||||||
uri := path.Join(pathAuthz, name)
|
uri := path.Join(pathAuthz, name)
|
||||||
|
|
||||||
authz := handlers.NewAuthzBuilder().WithConfig(config).WithEndpointConfig(endpoint).Build()
|
authz := handlers.NewAuthzBuilder().WithConfig(config).WithEndpointConfig(endpoint).Build()
|
||||||
// @HERE
|
|
||||||
handler := middlewares.Wrap(metricsVRMW, bridge(authz.Handler))
|
handler := middlewares.Wrap(metricsVRMW, bridge(authz.Handler))
|
||||||
|
|
||||||
switch name {
|
switch name {
|
||||||
|
@ -407,12 +404,6 @@ func handleRouter(config *schema.Configuration, providers middlewares.Providers)
|
||||||
return handler
|
return handler
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleGRCP(server *grpc.Server, config *schema.Configuration, providers middlewares.Providers) {
|
|
||||||
// Register endpoints
|
|
||||||
healthpb.RegisterHealthServer(server, &handlers.HealthEndpoint{})
|
|
||||||
autha.RegisterAuthorizationServer(server, handlers.NewAuthzGRCP(config, providers))
|
|
||||||
}
|
|
||||||
|
|
||||||
func handleMetrics(path string) fasthttp.RequestHandler {
|
func handleMetrics(path string) fasthttp.RequestHandler {
|
||||||
r := router.New()
|
r := router.New()
|
||||||
|
|
||||||
|
|
|
@ -9,8 +9,6 @@ import (
|
||||||
|
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
"github.com/valyala/fasthttp"
|
"github.com/valyala/fasthttp"
|
||||||
"google.golang.org/grpc"
|
|
||||||
"google.golang.org/grpc/credentials"
|
|
||||||
|
|
||||||
"github.com/authelia/authelia/v4/internal/configuration/schema"
|
"github.com/authelia/authelia/v4/internal/configuration/schema"
|
||||||
"github.com/authelia/authelia/v4/internal/logging"
|
"github.com/authelia/authelia/v4/internal/logging"
|
||||||
|
@ -46,13 +44,30 @@ func CreateDefaultServer(config *schema.Configuration, providers middlewares.Pro
|
||||||
if config.Server.TLS.Certificate != "" && config.Server.TLS.Key != "" {
|
if config.Server.TLS.Certificate != "" && config.Server.TLS.Key != "" {
|
||||||
isTLS, connectionScheme = true, schemeHTTPS
|
isTLS, connectionScheme = true, schemeHTTPS
|
||||||
|
|
||||||
tlsConfig, err := loadTLSCertificates(config)
|
if err = server.AppendCert(config.Server.TLS.Certificate, config.Server.TLS.Key); err != nil {
|
||||||
if err != nil {
|
return nil, nil, nil, false, fmt.Errorf("unable to load tls server certificate '%s' or private key '%s': %w", config.Server.TLS.Certificate, config.Server.TLS.Key, err)
|
||||||
return nil, nil, nil, false, fmt.Errorf("HTTP server: %w", err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply configuration
|
if len(config.Server.TLS.ClientCertificates) > 0 {
|
||||||
listener = tls.NewListener(listener, tlsConfig.Clone())
|
caCertPool := x509.NewCertPool()
|
||||||
|
|
||||||
|
var cert []byte
|
||||||
|
|
||||||
|
for _, path := range config.Server.TLS.ClientCertificates {
|
||||||
|
if cert, err = os.ReadFile(path); err != nil {
|
||||||
|
return nil, nil, nil, false, fmt.Errorf("unable to load tls client certificate '%s': %w", path, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
caCertPool.AppendCertsFromPEM(cert)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ClientCAs should never be nil, otherwise the system cert pool is used for client authentication
|
||||||
|
// but we don't want everybody on the Internet to be able to authenticate.
|
||||||
|
server.TLSConfig.ClientCAs = caCertPool
|
||||||
|
server.TLSConfig.ClientAuth = tls.RequireAndVerifyClientCert
|
||||||
|
}
|
||||||
|
|
||||||
|
listener = tls.NewListener(listener, server.TLSConfig.Clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = writeHealthCheckEnv(config.Server.DisableHealthcheck, connectionScheme, config.Server.Address.Hostname(),
|
if err = writeHealthCheckEnv(config.Server.DisableHealthcheck, connectionScheme, config.Server.Address.Hostname(),
|
||||||
|
@ -93,72 +108,3 @@ func CreateMetricsServer(config *schema.Configuration, providers middlewares.Pro
|
||||||
|
|
||||||
return server, listener, []string{config.Telemetry.Metrics.Address.Path()}, false, nil
|
return server, listener, []string{config.Telemetry.Metrics.Address.Path()}, false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateGRPCServer creates a server for handling gRPC authentication requests from an envoy proxy.
|
|
||||||
func CreateGRPCServer(config *schema.Configuration, providers middlewares.Providers) (server *grpc.Server, listener net.Listener, tls bool, err error) {
|
|
||||||
if config.Server.GRPC.Address == nil {
|
|
||||||
return nil, nil, false, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initialize gPRC server
|
|
||||||
lis, err := config.Server.GRPC.Address.Listener()
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, false, fmt.Errorf("error occurred while attempting to initialize grcp server listener for address '%s': %w", config.Server.GRPC.Address, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
opts := []grpc.ServerOption{grpc.MaxConcurrentStreams(10)}
|
|
||||||
|
|
||||||
if config.Server.TLS.Certificate != "" && config.Server.TLS.Key != "" && !config.Server.GRPC.DisableTLS {
|
|
||||||
tlsConfig, err := loadTLSCertificates(config)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil, false, fmt.Errorf("gRPC server: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
opts = append(opts, grpc.Creds(credentials.NewTLS(tlsConfig)))
|
|
||||||
tls = true
|
|
||||||
}
|
|
||||||
|
|
||||||
s := grpc.NewServer(opts...)
|
|
||||||
handleGRCP(s, config, providers)
|
|
||||||
|
|
||||||
return s, lis, tls, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// loadTLSCertificates loads the server and client certificates from the files and returns a
|
|
||||||
// tls.Config object for the server
|
|
||||||
func loadTLSCertificates(config *schema.Configuration) (*tls.Config, error) {
|
|
||||||
|
|
||||||
// Load the server certificates
|
|
||||||
serverCert, err := tls.LoadX509KeyPair(config.Server.TLS.Certificate, config.Server.TLS.Key)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("unable to load server certificate '%s' or key '%s': %w", config.Server.TLS.Certificate, config.Server.TLS.Key, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create the tls configuration
|
|
||||||
tlsConfig := &tls.Config{
|
|
||||||
Certificates: []tls.Certificate{serverCert},
|
|
||||||
ClientAuth: tls.NoClientCert,
|
|
||||||
}
|
|
||||||
|
|
||||||
// Load client certificates
|
|
||||||
if len(config.Server.TLS.ClientCertificates) > 0 {
|
|
||||||
caCertPool := x509.NewCertPool()
|
|
||||||
|
|
||||||
var cert []byte
|
|
||||||
|
|
||||||
for _, path := range config.Server.TLS.ClientCertificates {
|
|
||||||
if cert, err = os.ReadFile(path); err != nil {
|
|
||||||
return nil, fmt.Errorf("unable to load tls client certificate '%s': %w", path, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
caCertPool.AppendCertsFromPEM(cert)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ClientCAs should never be nil, otherwise the system cert pool is used for client authentication,
|
|
||||||
// but we don't want everybody on the Internet to be able to authenticate.
|
|
||||||
tlsConfig.ClientCAs = caCertPool
|
|
||||||
tlsConfig.ClientAuth = tls.RequireAndVerifyClientCert
|
|
||||||
}
|
|
||||||
|
|
||||||
return tlsConfig, nil
|
|
||||||
}
|
|
||||||
|
|
|
@ -90,5 +90,5 @@ type Provider interface {
|
||||||
// RegulatorProvider is an interface providing storage capabilities for persisting any kind of data related to the regulator.
|
// RegulatorProvider is an interface providing storage capabilities for persisting any kind of data related to the regulator.
|
||||||
type RegulatorProvider interface {
|
type RegulatorProvider interface {
|
||||||
AppendAuthenticationLog(ctx context.Context, attempt model.AuthenticationAttempt) (err error)
|
AppendAuthenticationLog(ctx context.Context, attempt model.AuthenticationAttempt) (err error)
|
||||||
LoadAuthenticationLogs(ctx context.Context, username string, ip string, fromDate time.Time, limit, page int) (attempts []model.AuthenticationAttempt, err error)
|
LoadAuthenticationLogs(ctx context.Context, username string, fromDate time.Time, limit, page int) (attempts []model.AuthenticationAttempt, err error)
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,7 +33,6 @@ func NewSQLProvider(config *schema.Configuration, name, driverName, dataSourceNa
|
||||||
|
|
||||||
sqlInsertAuthenticationAttempt: fmt.Sprintf(queryFmtInsertAuthenticationLogEntry, tableAuthenticationLogs),
|
sqlInsertAuthenticationAttempt: fmt.Sprintf(queryFmtInsertAuthenticationLogEntry, tableAuthenticationLogs),
|
||||||
sqlSelectAuthenticationAttemptsByUsername: fmt.Sprintf(queryFmtSelect1FAAuthenticationLogEntryByUsername, tableAuthenticationLogs),
|
sqlSelectAuthenticationAttemptsByUsername: fmt.Sprintf(queryFmtSelect1FAAuthenticationLogEntryByUsername, tableAuthenticationLogs),
|
||||||
sqlSelectAuthenticationAttemptyByIP: fmt.Sprintf(queryFmtSelect1FAAuthenticationLogEntryByIP, tableAuthenticationLogs),
|
|
||||||
|
|
||||||
sqlInsertIdentityVerification: fmt.Sprintf(queryFmtInsertIdentityVerification, tableIdentityVerification),
|
sqlInsertIdentityVerification: fmt.Sprintf(queryFmtInsertIdentityVerification, tableIdentityVerification),
|
||||||
sqlConsumeIdentityVerification: fmt.Sprintf(queryFmtConsumeIdentityVerification, tableIdentityVerification),
|
sqlConsumeIdentityVerification: fmt.Sprintf(queryFmtConsumeIdentityVerification, tableIdentityVerification),
|
||||||
|
@ -150,7 +149,6 @@ type SQLProvider struct {
|
||||||
// Table: authentication_logs.
|
// Table: authentication_logs.
|
||||||
sqlInsertAuthenticationAttempt string
|
sqlInsertAuthenticationAttempt string
|
||||||
sqlSelectAuthenticationAttemptsByUsername string
|
sqlSelectAuthenticationAttemptsByUsername string
|
||||||
sqlSelectAuthenticationAttemptyByIP string
|
|
||||||
|
|
||||||
// Table: identity_verification.
|
// Table: identity_verification.
|
||||||
sqlInsertIdentityVerification string
|
sqlInsertIdentityVerification string
|
||||||
|
@ -1023,18 +1021,10 @@ func (p *SQLProvider) AppendAuthenticationLog(ctx context.Context, attempt model
|
||||||
}
|
}
|
||||||
|
|
||||||
// LoadAuthenticationLogs retrieve the latest failed authentications from the authentication log.
|
// LoadAuthenticationLogs retrieve the latest failed authentications from the authentication log.
|
||||||
func (p *SQLProvider) LoadAuthenticationLogs(ctx context.Context, username string, ip string, fromDate time.Time, limit, page int) (attempts []model.AuthenticationAttempt, err error) {
|
func (p *SQLProvider) LoadAuthenticationLogs(ctx context.Context, username string, fromDate time.Time, limit, page int) (attempts []model.AuthenticationAttempt, err error) {
|
||||||
attempts = make([]model.AuthenticationAttempt, 0, limit)
|
attempts = make([]model.AuthenticationAttempt, 0, limit)
|
||||||
|
|
||||||
// Dynmaic values based on ip / username ban
|
if err = p.db.SelectContext(ctx, &attempts, p.sqlSelectAuthenticationAttemptsByUsername, fromDate, username, limit, limit*page); err != nil {
|
||||||
query := p.sqlSelectAuthenticationAttemptsByUsername
|
|
||||||
placeholder := username
|
|
||||||
if p.config.Server.UseIPInsteadOfUserForBan {
|
|
||||||
query = p.sqlSelectAuthenticationAttemptyByIP
|
|
||||||
placeholder = ip
|
|
||||||
}
|
|
||||||
|
|
||||||
if err = p.db.SelectContext(ctx, &attempts, query, fromDate, placeholder, limit, limit*page); err != nil {
|
|
||||||
if errors.Is(err, sql.ErrNoRows) {
|
if errors.Is(err, sql.ErrNoRows) {
|
||||||
return nil, ErrNoAuthenticationLogs
|
return nil, ErrNoAuthenticationLogs
|
||||||
}
|
}
|
||||||
|
@ -1043,5 +1033,4 @@ func (p *SQLProvider) LoadAuthenticationLogs(ctx context.Context, username strin
|
||||||
}
|
}
|
||||||
|
|
||||||
return attempts, nil
|
return attempts, nil
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -71,7 +71,6 @@ func NewPostgreSQLProvider(config *schema.Configuration, caCertPool *x509.CertPo
|
||||||
|
|
||||||
provider.sqlInsertAuthenticationAttempt = provider.db.Rebind(provider.sqlInsertAuthenticationAttempt)
|
provider.sqlInsertAuthenticationAttempt = provider.db.Rebind(provider.sqlInsertAuthenticationAttempt)
|
||||||
provider.sqlSelectAuthenticationAttemptsByUsername = provider.db.Rebind(provider.sqlSelectAuthenticationAttemptsByUsername)
|
provider.sqlSelectAuthenticationAttemptsByUsername = provider.db.Rebind(provider.sqlSelectAuthenticationAttemptsByUsername)
|
||||||
provider.sqlSelectAuthenticationAttemptyByIP = provider.db.Rebind(provider.sqlSelectAuthenticationAttemptyByIP)
|
|
||||||
|
|
||||||
provider.sqlInsertMigration = provider.db.Rebind(provider.sqlInsertMigration)
|
provider.sqlInsertMigration = provider.db.Rebind(provider.sqlInsertMigration)
|
||||||
provider.sqlSelectMigrations = provider.db.Rebind(provider.sqlSelectMigrations)
|
provider.sqlSelectMigrations = provider.db.Rebind(provider.sqlSelectMigrations)
|
||||||
|
|
|
@ -211,14 +211,6 @@ const (
|
||||||
ORDER BY time DESC
|
ORDER BY time DESC
|
||||||
LIMIT ?
|
LIMIT ?
|
||||||
OFFSET ?;`
|
OFFSET ?;`
|
||||||
|
|
||||||
queryFmtSelect1FAAuthenticationLogEntryByIP = `
|
|
||||||
SELECT time, successful, username
|
|
||||||
FROM %s
|
|
||||||
WHERE time > ? AND remote_ip = ? AND auth_type = '1FA' AND banned = FALSE
|
|
||||||
ORDER BY time DESC
|
|
||||||
LIMIT ?
|
|
||||||
OFFSET ?;`
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|
|
@ -10,9 +10,6 @@ server:
|
||||||
tls:
|
tls:
|
||||||
certificate: /pki/public.backend.crt
|
certificate: /pki/public.backend.crt
|
||||||
key: /pki/private.backend.pem
|
key: /pki/private.backend.pem
|
||||||
grpc:
|
|
||||||
address: 'tcp://0.0.0.0:9092'
|
|
||||||
disableTLS: false
|
|
||||||
|
|
||||||
telemetry:
|
telemetry:
|
||||||
metrics:
|
metrics:
|
||||||
|
@ -20,7 +17,7 @@ telemetry:
|
||||||
address: tcp://0.0.0.0:9959
|
address: tcp://0.0.0.0:9959
|
||||||
|
|
||||||
log:
|
log:
|
||||||
level: trace
|
level: debug
|
||||||
|
|
||||||
authentication_backend:
|
authentication_backend:
|
||||||
file:
|
file:
|
||||||
|
@ -33,8 +30,6 @@ session:
|
||||||
cookies:
|
cookies:
|
||||||
- domain: 'example.com'
|
- domain: 'example.com'
|
||||||
authelia_url: 'https://login.example.com:8080'
|
authelia_url: 'https://login.example.com:8080'
|
||||||
- domain: 'rpjosh.de'
|
|
||||||
authelia_url: 'https://ubuntugui.rpjosh.de:9091'
|
|
||||||
|
|
||||||
storage:
|
storage:
|
||||||
encryption_key: a_not_so_secure_encryption_key
|
encryption_key: a_not_so_secure_encryption_key
|
||||||
|
@ -88,18 +83,6 @@ access_control:
|
||||||
subject: "user:bob"
|
subject: "user:bob"
|
||||||
policy: two_factor
|
policy: two_factor
|
||||||
|
|
||||||
- domain: auth.rpjosh.de
|
|
||||||
policy: bypass
|
|
||||||
|
|
||||||
- domain: datenbank.rpjosh.de
|
|
||||||
resources:
|
|
||||||
- "^/$"
|
|
||||||
policy: bypass
|
|
||||||
- domain: datenbank.rpjosh.de
|
|
||||||
resources:
|
|
||||||
- "^/hi.*$"
|
|
||||||
policy: one_factor
|
|
||||||
|
|
||||||
|
|
||||||
regulation:
|
regulation:
|
||||||
# Set it to 0 to disable max_retries.
|
# Set it to 0 to disable max_retries.
|
||||||
|
|
|
@ -17,4 +17,3 @@ ENV PATH="/app:${PATH}" \
|
||||||
VOLUME /config
|
VOLUME /config
|
||||||
|
|
||||||
EXPOSE 9091
|
EXPOSE 9091
|
||||||
EXPOSE 9092
|
|
|
@ -2,4 +2,4 @@
|
||||||
|
|
||||||
set -x
|
set -x
|
||||||
|
|
||||||
pnpm start
|
pnpm install --frozen-lockfile && pnpm start
|
|
@ -2,7 +2,7 @@
|
||||||
version: '3'
|
version: '3'
|
||||||
services:
|
services:
|
||||||
traefik:
|
traefik:
|
||||||
image: traefik:v2.10.3
|
image: traefik:v2.10.1
|
||||||
volumes:
|
volumes:
|
||||||
- '/var/run/docker.sock:/var/run/docker.sock'
|
- '/var/run/docker.sock:/var/run/docker.sock'
|
||||||
labels:
|
labels:
|
||||||
|
|
|
@ -19,18 +19,18 @@
|
||||||
"@fortawesome/free-solid-svg-icons": "6.4.0",
|
"@fortawesome/free-solid-svg-icons": "6.4.0",
|
||||||
"@fortawesome/react-fontawesome": "0.2.0",
|
"@fortawesome/react-fontawesome": "0.2.0",
|
||||||
"@mui/icons-material": "5.11.16",
|
"@mui/icons-material": "5.11.16",
|
||||||
"@mui/material": "5.13.6",
|
"@mui/material": "5.13.5",
|
||||||
"@mui/styles": "5.13.2",
|
"@mui/styles": "5.13.2",
|
||||||
"axios": "1.4.0",
|
"axios": "1.4.0",
|
||||||
"broadcast-channel": "5.1.0",
|
"broadcast-channel": "5.1.0",
|
||||||
"classnames": "2.3.2",
|
"classnames": "2.3.2",
|
||||||
"i18next": "23.2.3",
|
"i18next": "23.1.0",
|
||||||
"i18next-browser-languagedetector": "7.0.2",
|
"i18next-browser-languagedetector": "7.0.2",
|
||||||
"i18next-http-backend": "2.2.1",
|
"i18next-http-backend": "2.2.1",
|
||||||
"qrcode.react": "3.1.0",
|
"qrcode.react": "3.1.0",
|
||||||
"react": "18.2.0",
|
"react": "18.2.0",
|
||||||
"react-dom": "18.2.0",
|
"react-dom": "18.2.0",
|
||||||
"react-i18next": "13.0.1",
|
"react-i18next": "13.0.0",
|
||||||
"react-loading": "2.0.3",
|
"react-loading": "2.0.3",
|
||||||
"react-router-dom": "6.13.0",
|
"react-router-dom": "6.13.0",
|
||||||
"react18-input-otp": "1.1.3",
|
"react18-input-otp": "1.1.3",
|
||||||
|
@ -80,7 +80,7 @@
|
||||||
"@typescript-eslint/parser": "5.60.0",
|
"@typescript-eslint/parser": "5.60.0",
|
||||||
"@vitejs/plugin-react": "4.0.1",
|
"@vitejs/plugin-react": "4.0.1",
|
||||||
"@vitest/coverage-istanbul": "0.32.2",
|
"@vitest/coverage-istanbul": "0.32.2",
|
||||||
"esbuild": "0.18.6",
|
"esbuild": "0.18.4",
|
||||||
"eslint": "8.43.0",
|
"eslint": "8.43.0",
|
||||||
"eslint-config-prettier": "8.8.0",
|
"eslint-config-prettier": "8.8.0",
|
||||||
"eslint-config-react-app": "7.0.1",
|
"eslint-config-react-app": "7.0.1",
|
||||||
|
|
|
@ -28,10 +28,10 @@ dependencies:
|
||||||
version: 0.2.0(@fortawesome/fontawesome-svg-core@6.4.0)(react@18.2.0)
|
version: 0.2.0(@fortawesome/fontawesome-svg-core@6.4.0)(react@18.2.0)
|
||||||
'@mui/icons-material':
|
'@mui/icons-material':
|
||||||
specifier: 5.11.16
|
specifier: 5.11.16
|
||||||
version: 5.11.16(@mui/material@5.13.6)(@types/react@18.2.13)(react@18.2.0)
|
version: 5.11.16(@mui/material@5.13.5)(@types/react@18.2.13)(react@18.2.0)
|
||||||
'@mui/material':
|
'@mui/material':
|
||||||
specifier: 5.13.6
|
specifier: 5.13.5
|
||||||
version: 5.13.6(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(@types/react@18.2.13)(react-dom@18.2.0)(react@18.2.0)
|
version: 5.13.5(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(@types/react@18.2.13)(react-dom@18.2.0)(react@18.2.0)
|
||||||
'@mui/styles':
|
'@mui/styles':
|
||||||
specifier: 5.13.2
|
specifier: 5.13.2
|
||||||
version: 5.13.2(@types/react@18.2.13)(react@18.2.0)
|
version: 5.13.2(@types/react@18.2.13)(react@18.2.0)
|
||||||
|
@ -45,8 +45,8 @@ dependencies:
|
||||||
specifier: 2.3.2
|
specifier: 2.3.2
|
||||||
version: 2.3.2
|
version: 2.3.2
|
||||||
i18next:
|
i18next:
|
||||||
specifier: 23.2.3
|
specifier: 23.1.0
|
||||||
version: 23.2.3
|
version: 23.1.0
|
||||||
i18next-browser-languagedetector:
|
i18next-browser-languagedetector:
|
||||||
specifier: 7.0.2
|
specifier: 7.0.2
|
||||||
version: 7.0.2
|
version: 7.0.2
|
||||||
|
@ -63,8 +63,8 @@ dependencies:
|
||||||
specifier: 18.2.0
|
specifier: 18.2.0
|
||||||
version: 18.2.0(react@18.2.0)
|
version: 18.2.0(react@18.2.0)
|
||||||
react-i18next:
|
react-i18next:
|
||||||
specifier: 13.0.1
|
specifier: 13.0.0
|
||||||
version: 13.0.1(i18next@23.2.3)(react-dom@18.2.0)(react@18.2.0)
|
version: 13.0.0(i18next@23.1.0)(react-dom@18.2.0)(react@18.2.0)
|
||||||
react-loading:
|
react-loading:
|
||||||
specifier: 2.0.3
|
specifier: 2.0.3
|
||||||
version: 2.0.3(prop-types@15.8.1)(react@18.2.0)
|
version: 2.0.3(prop-types@15.8.1)(react@18.2.0)
|
||||||
|
@ -122,8 +122,8 @@ devDependencies:
|
||||||
specifier: 0.32.2
|
specifier: 0.32.2
|
||||||
version: 0.32.2(vitest@0.32.2)
|
version: 0.32.2(vitest@0.32.2)
|
||||||
esbuild:
|
esbuild:
|
||||||
specifier: 0.18.6
|
specifier: 0.18.4
|
||||||
version: 0.18.6
|
version: 0.18.4
|
||||||
eslint:
|
eslint:
|
||||||
specifier: 8.43.0
|
specifier: 8.43.0
|
||||||
version: 8.43.0
|
version: 8.43.0
|
||||||
|
@ -1938,8 +1938,8 @@ packages:
|
||||||
dev: true
|
dev: true
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
/@esbuild/android-arm64@0.18.6:
|
/@esbuild/android-arm64@0.18.4:
|
||||||
resolution: {integrity: sha512-pL0Ci8P9q1sWbtPx8CXbc8JvPvvYdJJQ+LO09PLFsbz3aYNdFBGWJjiHU+CaObO4Ames+GOFpXRAJZS2L3ZK/A==}
|
resolution: {integrity: sha512-yQVgO+V307hA2XhzELQ6F91CBGX7gSnlVGAj5YIqjQOxThDpM7fOcHT2YLJbE6gNdPtgRSafQrsK8rJ9xHCaZg==}
|
||||||
engines: {node: '>=12'}
|
engines: {node: '>=12'}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [android]
|
os: [android]
|
||||||
|
@ -1965,8 +1965,8 @@ packages:
|
||||||
dev: true
|
dev: true
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
/@esbuild/android-arm@0.18.6:
|
/@esbuild/android-arm@0.18.4:
|
||||||
resolution: {integrity: sha512-J3lwhDSXBBppSzm/LC1uZ8yKSIpExc+5T8MxrYD9KNVZG81FOAu2VF2gXi/6A/LwDDQQ+b6DpQbYlo3VwxFepQ==}
|
resolution: {integrity: sha512-yKmQC9IiuvHdsNEbPHSprnMHg6OhL1cSeQZLzPpgzJBJ9ppEg9GAZN8MKj1TcmB4tZZUrq5xjK7KCmhwZP8iDA==}
|
||||||
engines: {node: '>=12'}
|
engines: {node: '>=12'}
|
||||||
cpu: [arm]
|
cpu: [arm]
|
||||||
os: [android]
|
os: [android]
|
||||||
|
@ -1983,8 +1983,8 @@ packages:
|
||||||
dev: true
|
dev: true
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
/@esbuild/android-x64@0.18.6:
|
/@esbuild/android-x64@0.18.4:
|
||||||
resolution: {integrity: sha512-hE2vZxOlJ05aY28lUpB0y0RokngtZtcUB+TVl9vnLEnY0z/8BicSvrkThg5/iI1rbf8TwXrbr2heEjl9fLf+EA==}
|
resolution: {integrity: sha512-yLKXMxQg6sk1ntftxQ5uwyVgG4/S2E7UoOCc5N4YZW7fdkfRiYEXqm7CMuIfY2Vs3FTrNyKmSfNevIuIvJnMww==}
|
||||||
engines: {node: '>=12'}
|
engines: {node: '>=12'}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [android]
|
os: [android]
|
||||||
|
@ -2001,8 +2001,8 @@ packages:
|
||||||
dev: true
|
dev: true
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
/@esbuild/darwin-arm64@0.18.6:
|
/@esbuild/darwin-arm64@0.18.4:
|
||||||
resolution: {integrity: sha512-/tuyl4R+QhhoROQtuQj9E/yfJtZNdv2HKaHwYhhHGQDN1Teziem2Kh7BWQMumfiY7Lu9g5rO7scWdGE4OsQ6MQ==}
|
resolution: {integrity: sha512-MVPEoZjZpk2xQ1zckZrb8eQuQib+QCzdmMs3YZAYEQPg+Rztk5pUxGyk8htZOC8Z38NMM29W+MqY9Sqo/sDGKw==}
|
||||||
engines: {node: '>=12'}
|
engines: {node: '>=12'}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [darwin]
|
os: [darwin]
|
||||||
|
@ -2019,8 +2019,8 @@ packages:
|
||||||
dev: true
|
dev: true
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
/@esbuild/darwin-x64@0.18.6:
|
/@esbuild/darwin-x64@0.18.4:
|
||||||
resolution: {integrity: sha512-L7IQga2pDT+14Ti8HZwsVfbCjuKP4U213T3tuPggOzyK/p4KaUJxQFXJgfUFHKzU0zOXx8QcYRYZf0hSQtppkw==}
|
resolution: {integrity: sha512-uEsRtYRUDsz7i2tXg/t/SyF+5gU1cvi9B6B8i5ebJgtUUHJYWyIPIesmIOL4/+bywjxsDMA/XrNFMgMffLnh5A==}
|
||||||
engines: {node: '>=12'}
|
engines: {node: '>=12'}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [darwin]
|
os: [darwin]
|
||||||
|
@ -2037,8 +2037,8 @@ packages:
|
||||||
dev: true
|
dev: true
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
/@esbuild/freebsd-arm64@0.18.6:
|
/@esbuild/freebsd-arm64@0.18.4:
|
||||||
resolution: {integrity: sha512-bq10jFv42V20Kk77NvmO+WEZaLHBKuXcvEowixnBOMkaBgS7kQaqTc77ZJDbsUpXU3KKNLQFZctfaeINmeTsZA==}
|
resolution: {integrity: sha512-I8EOigqWnOHRin6Zp5Y1cfH3oT54bd7Sdz/VnpUNksbOtfp8IWRTH4pgkgO5jWaRQPjCpJcOpdRjYAMjPt8wXg==}
|
||||||
engines: {node: '>=12'}
|
engines: {node: '>=12'}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [freebsd]
|
os: [freebsd]
|
||||||
|
@ -2055,8 +2055,8 @@ packages:
|
||||||
dev: true
|
dev: true
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
/@esbuild/freebsd-x64@0.18.6:
|
/@esbuild/freebsd-x64@0.18.4:
|
||||||
resolution: {integrity: sha512-HbDLlkDZqUMBQaiday0pJzB6/8Xx/10dI3xRebJBReOEeDSeS+7GzTtW9h8ZnfB7/wBCqvtAjGtWQLTNPbR2+g==}
|
resolution: {integrity: sha512-1bHfgMz/cNMjbpsYxjVgMJ1iwKq+NdDPlACBrWULD7ZdFmBQrhMicMaKb5CdmdVyvIwXmasOuF4r6Iq574kUTA==}
|
||||||
engines: {node: '>=12'}
|
engines: {node: '>=12'}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [freebsd]
|
os: [freebsd]
|
||||||
|
@ -2073,8 +2073,8 @@ packages:
|
||||||
dev: true
|
dev: true
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
/@esbuild/linux-arm64@0.18.6:
|
/@esbuild/linux-arm64@0.18.4:
|
||||||
resolution: {integrity: sha512-NMY9yg/88MskEZH2s4i6biz/3av+M8xY5ua4HE7CCz5DBz542cr7REe317+v7oKjnYBCijHpkzo5vU85bkXQmQ==}
|
resolution: {integrity: sha512-J42vLHaYREyiBwH0eQE4/7H1DTfZx8FuxyWSictx4d7ezzuKE3XOkIvOg+SQzRz7T9HLVKzq2tvbAov4UfufBw==}
|
||||||
engines: {node: '>=12'}
|
engines: {node: '>=12'}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
@ -2091,8 +2091,8 @@ packages:
|
||||||
dev: true
|
dev: true
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
/@esbuild/linux-arm@0.18.6:
|
/@esbuild/linux-arm@0.18.4:
|
||||||
resolution: {integrity: sha512-C+5kb6rgsGMmvIdUI7v1PPgC98A6BMv233e97aXZ5AE03iMdlILFD/20HlHrOi0x2CzbspXn9HOnlE4/Ijn5Kw==}
|
resolution: {integrity: sha512-4XCGqM/Ay1LCXUBH59bL4JbSbbTK1K22dWHymWMGaEh2sQCDOUw+OQxozYV/YdBb91leK2NbuSrE2BRamwgaYw==}
|
||||||
engines: {node: '>=12'}
|
engines: {node: '>=12'}
|
||||||
cpu: [arm]
|
cpu: [arm]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
@ -2109,8 +2109,8 @@ packages:
|
||||||
dev: true
|
dev: true
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
/@esbuild/linux-ia32@0.18.6:
|
/@esbuild/linux-ia32@0.18.4:
|
||||||
resolution: {integrity: sha512-AXazA0ljvQEp7cA9jscABNXsjodKbEcqPcAE3rDzKN82Vb3lYOq6INd+HOCA7hk8IegEyHW4T72Z7QGIhyCQEA==}
|
resolution: {integrity: sha512-4ksIqFwhq7OExty7Sl1n0vqQSCqTG4sU6i99G2yuMr28CEOUZ/60N+IO9hwI8sIxBqmKmDgncE1n5CMu/3m0IA==}
|
||||||
engines: {node: '>=12'}
|
engines: {node: '>=12'}
|
||||||
cpu: [ia32]
|
cpu: [ia32]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
@ -2136,8 +2136,8 @@ packages:
|
||||||
dev: true
|
dev: true
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
/@esbuild/linux-loong64@0.18.6:
|
/@esbuild/linux-loong64@0.18.4:
|
||||||
resolution: {integrity: sha512-JjBf7TwY7ldcPgHYt9UcrjZB03+WZqg/jSwMAfzOzM5ZG+tu5umUqzy5ugH/crGI4eoDIhSOTDp1NL3Uo/05Fw==}
|
resolution: {integrity: sha512-bsWtoVHkGQgAsFXioDueXRiUIfSGrVkJjBBz4gcBJxXcD461cWFQFyu8Fxdj9TP+zEeqJ8C/O4LFFMBNi6Fscw==}
|
||||||
engines: {node: '>=12'}
|
engines: {node: '>=12'}
|
||||||
cpu: [loong64]
|
cpu: [loong64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
@ -2154,8 +2154,8 @@ packages:
|
||||||
dev: true
|
dev: true
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
/@esbuild/linux-mips64el@0.18.6:
|
/@esbuild/linux-mips64el@0.18.4:
|
||||||
resolution: {integrity: sha512-kATNsslryVxcH1sO3KP2nnyUWtZZVkgyhAUnyTVVa0OQQ9pmDRjTpHaE+2EQHoCM5wt/uav2edrAUqbwn3tkKQ==}
|
resolution: {integrity: sha512-LRD9Fu8wJQgIOOV1o3nRyzrheFYjxA0C1IVWZ93eNRRWBKgarYFejd5WBtrp43cE4y4D4t3qWWyklm73Mrsd/g==}
|
||||||
engines: {node: '>=12'}
|
engines: {node: '>=12'}
|
||||||
cpu: [mips64el]
|
cpu: [mips64el]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
@ -2172,8 +2172,8 @@ packages:
|
||||||
dev: true
|
dev: true
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
/@esbuild/linux-ppc64@0.18.6:
|
/@esbuild/linux-ppc64@0.18.4:
|
||||||
resolution: {integrity: sha512-B+wTKz+8pi7mcWXFQV0LA79dJ+qhiut5uK9q0omoKnq8yRIwQJwfg3/vclXoqqcX89Ri5Y5538V0Se2v5qlcLA==}
|
resolution: {integrity: sha512-jtQgoZjM92gauVRxNaaG/TpL3Pr4WcL3Pwqi9QgdrBGrEXzB+twohQiWNSTycs6lUygakos4mm2h0B9/SHveng==}
|
||||||
engines: {node: '>=12'}
|
engines: {node: '>=12'}
|
||||||
cpu: [ppc64]
|
cpu: [ppc64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
@ -2190,8 +2190,8 @@ packages:
|
||||||
dev: true
|
dev: true
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
/@esbuild/linux-riscv64@0.18.6:
|
/@esbuild/linux-riscv64@0.18.4:
|
||||||
resolution: {integrity: sha512-h44RBLVXFUSjvhOfseE+5UxQ/r9LVeqK2S8JziJKOm9W7SePYRPDyn7MhzhNCCFPkcjIy+soCxfhlJXHXXCR0A==}
|
resolution: {integrity: sha512-7WaU/kRZG0VCV09Xdlkg6LNAsfU9SAxo6XEdaZ8ffO4lh+DZoAhGTx7+vTMOXKxa+r2w1LYDGxfJa2rcgagMRA==}
|
||||||
engines: {node: '>=12'}
|
engines: {node: '>=12'}
|
||||||
cpu: [riscv64]
|
cpu: [riscv64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
@ -2208,8 +2208,8 @@ packages:
|
||||||
dev: true
|
dev: true
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
/@esbuild/linux-s390x@0.18.6:
|
/@esbuild/linux-s390x@0.18.4:
|
||||||
resolution: {integrity: sha512-FlYpyr2Xc2AUePoAbc84NRV+mj7xpsISeQ36HGf9etrY5rTBEA+IU9HzWVmw5mDFtC62EQxzkLRj8h5Hq85yOQ==}
|
resolution: {integrity: sha512-D19ed0xreKQvC5t+ArE2njSnm18WPpE+1fhwaiJHf+Xwqsq+/SUaV8Mx0M27nszdU+Atq1HahrgCOZCNNEASUg==}
|
||||||
engines: {node: '>=12'}
|
engines: {node: '>=12'}
|
||||||
cpu: [s390x]
|
cpu: [s390x]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
@ -2226,8 +2226,8 @@ packages:
|
||||||
dev: true
|
dev: true
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
/@esbuild/linux-x64@0.18.6:
|
/@esbuild/linux-x64@0.18.4:
|
||||||
resolution: {integrity: sha512-Mc4EUSYwzLci77u0Kao6ajB2WbTe5fNc7+lHwS3a+vJISC/oprwURezUYu1SdWAYoczbsyOvKAJwuNftoAdjjg==}
|
resolution: {integrity: sha512-Rx3AY1sxyiO/gvCGP00nL69L60dfmWyjKWY06ugpB8Ydpdsfi3BHW58HWC24K3CAjAPSwxcajozC2PzA9JBS1g==}
|
||||||
engines: {node: '>=12'}
|
engines: {node: '>=12'}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [linux]
|
os: [linux]
|
||||||
|
@ -2244,8 +2244,8 @@ packages:
|
||||||
dev: true
|
dev: true
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
/@esbuild/netbsd-x64@0.18.6:
|
/@esbuild/netbsd-x64@0.18.4:
|
||||||
resolution: {integrity: sha512-3hgZlp7NqIM5lNG3fpdhBI5rUnPmdahraSmwAi+YX/bp7iZ7mpTv2NkypGs/XngdMtpzljICxnUG3uPfqLFd3w==}
|
resolution: {integrity: sha512-AaShPmN9c6w1mKRpliKFlaWcSkpBT4KOlk93UfFgeI3F3cbjzdDKGsbKnOZozmYbE1izZKLmNJiW0sFM+A5JPA==}
|
||||||
engines: {node: '>=12'}
|
engines: {node: '>=12'}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [netbsd]
|
os: [netbsd]
|
||||||
|
@ -2262,8 +2262,8 @@ packages:
|
||||||
dev: true
|
dev: true
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
/@esbuild/openbsd-x64@0.18.6:
|
/@esbuild/openbsd-x64@0.18.4:
|
||||||
resolution: {integrity: sha512-aEWTdZQHtSRROlDYn7ygB8yAqtnall/UnmoVIJVqccKitkAWVVSYocQUWrBOxLEFk8XdlRouVrLZe6WXszyviA==}
|
resolution: {integrity: sha512-tRGvGwou3BrvHVvF8HxTqEiC5VtPzySudS9fh2jBIKpLX7HCW8jIkW+LunkFDNwhslx4xMAgh0jAHsx/iCymaQ==}
|
||||||
engines: {node: '>=12'}
|
engines: {node: '>=12'}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [openbsd]
|
os: [openbsd]
|
||||||
|
@ -2280,8 +2280,8 @@ packages:
|
||||||
dev: true
|
dev: true
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
/@esbuild/sunos-x64@0.18.6:
|
/@esbuild/sunos-x64@0.18.4:
|
||||||
resolution: {integrity: sha512-uxk/5yAGpjKZUHOECtI9W+9IcLjKj+2m0qf+RG7f7eRBHr8wP6wsr3XbNbgtOD1qSpPapd6R2ZfSeXTkCcAo5g==}
|
resolution: {integrity: sha512-acORFDI95GKhmAnlH8EarBeuqoy/j3yxIU+FDB91H3+ZON+8HhTadtT450YkaMzX6lEWbhi+mjVUCj00M5yyOQ==}
|
||||||
engines: {node: '>=12'}
|
engines: {node: '>=12'}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [sunos]
|
os: [sunos]
|
||||||
|
@ -2298,8 +2298,8 @@ packages:
|
||||||
dev: true
|
dev: true
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
/@esbuild/win32-arm64@0.18.6:
|
/@esbuild/win32-arm64@0.18.4:
|
||||||
resolution: {integrity: sha512-oXlXGS9zvNCGoAT/tLHAsFKrIKye1JaIIP0anCdpaI+Dc10ftaNZcqfLzEwyhdzFAYInXYH4V7kEdH4hPyo9GA==}
|
resolution: {integrity: sha512-1NxP+iOk8KSvS1L9SSxEvBAJk39U0GiGZkiiJGbuDF9G4fG7DSDw6XLxZMecAgmvQrwwx7yVKdNN3GgNh0UfKg==}
|
||||||
engines: {node: '>=12'}
|
engines: {node: '>=12'}
|
||||||
cpu: [arm64]
|
cpu: [arm64]
|
||||||
os: [win32]
|
os: [win32]
|
||||||
|
@ -2316,8 +2316,8 @@ packages:
|
||||||
dev: true
|
dev: true
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
/@esbuild/win32-ia32@0.18.6:
|
/@esbuild/win32-ia32@0.18.4:
|
||||||
resolution: {integrity: sha512-qh7IcAHUvvmMBmoIG+V+BbE9ZWSR0ohF51e5g8JZvU08kZF58uDFL5tHs0eoYz31H6Finv17te3W3QB042GqVA==}
|
resolution: {integrity: sha512-OKr8jze93vbgqZ/r23woWciTixUwLa976C9W7yNBujtnVHyvsL/ocYG61tsktUfJOpyIz5TsohkBZ6Lo2+PCcQ==}
|
||||||
engines: {node: '>=12'}
|
engines: {node: '>=12'}
|
||||||
cpu: [ia32]
|
cpu: [ia32]
|
||||||
os: [win32]
|
os: [win32]
|
||||||
|
@ -2334,8 +2334,8 @@ packages:
|
||||||
dev: true
|
dev: true
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
/@esbuild/win32-x64@0.18.6:
|
/@esbuild/win32-x64@0.18.4:
|
||||||
resolution: {integrity: sha512-9UDwkz7Wlm4N9jnv+4NL7F8vxLhSZfEkRArz2gD33HesAFfMLGIGNVXRoIHtWNw8feKsnGly9Hq1EUuRkWl0zA==}
|
resolution: {integrity: sha512-qJr3wVvcLjPFcV4AMDS3iquhBfTef2zo/jlm8RMxmiRp3Vy2HY8WMxrykJlcbCnqLXZPA0YZxZGND6eug85ogg==}
|
||||||
engines: {node: '>=12'}
|
engines: {node: '>=12'}
|
||||||
cpu: [x64]
|
cpu: [x64]
|
||||||
os: [win32]
|
os: [win32]
|
||||||
|
@ -2542,8 +2542,8 @@ packages:
|
||||||
tsconfig-paths: 3.14.2
|
tsconfig-paths: 3.14.2
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/@mui/base@5.0.0-beta.5(@types/react@18.2.13)(react-dom@18.2.0)(react@18.2.0):
|
/@mui/base@5.0.0-beta.4(@types/react@18.2.13)(react-dom@18.2.0)(react@18.2.0):
|
||||||
resolution: {integrity: sha512-vy3TWLQYdGNecTaufR4wDNQFV2WEg6wRPi6BVbx6q1vP3K1mbxIn1+XOqOzfYBXjFHvMx0gZAo2TgWbaqfgvAA==}
|
resolution: {integrity: sha512-ejhtqYJpjDgHGEljjMBQWZ22yEK0OzIXNa7toJmmXsP4TT3W7xVy8bTJ0TniPDf+JNjrsgfgiFTDGdlEhV1E+g==}
|
||||||
engines: {node: '>=12.0.0'}
|
engines: {node: '>=12.0.0'}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
'@types/react': ^17.0.0 || ^18.0.0 || 18
|
'@types/react': ^17.0.0 || ^18.0.0 || 18
|
||||||
|
@ -2556,7 +2556,7 @@ packages:
|
||||||
'@babel/runtime': 7.22.5
|
'@babel/runtime': 7.22.5
|
||||||
'@emotion/is-prop-valid': 1.2.1
|
'@emotion/is-prop-valid': 1.2.1
|
||||||
'@mui/types': 7.2.4(@types/react@18.2.13)
|
'@mui/types': 7.2.4(@types/react@18.2.13)
|
||||||
'@mui/utils': 5.13.6(react@18.2.0)
|
'@mui/utils': 5.13.1(react@18.2.0)
|
||||||
'@popperjs/core': 2.11.8
|
'@popperjs/core': 2.11.8
|
||||||
'@types/react': 18.2.13
|
'@types/react': 18.2.13
|
||||||
clsx: 1.2.1
|
clsx: 1.2.1
|
||||||
|
@ -2570,7 +2570,7 @@ packages:
|
||||||
resolution: {integrity: sha512-yFrMWcrlI0TqRN5jpb6Ma9iI7sGTHpytdzzL33oskFHNQ8UgrtPas33Y1K7sWAMwCrr1qbWDrOHLAQG4tAzuSw==}
|
resolution: {integrity: sha512-yFrMWcrlI0TqRN5jpb6Ma9iI7sGTHpytdzzL33oskFHNQ8UgrtPas33Y1K7sWAMwCrr1qbWDrOHLAQG4tAzuSw==}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/@mui/icons-material@5.11.16(@mui/material@5.13.6)(@types/react@18.2.13)(react@18.2.0):
|
/@mui/icons-material@5.11.16(@mui/material@5.13.5)(@types/react@18.2.13)(react@18.2.0):
|
||||||
resolution: {integrity: sha512-oKkx9z9Kwg40NtcIajF9uOXhxiyTZrrm9nmIJ4UjkU2IdHpd4QVLbCc/5hZN/y0C6qzi2Zlxyr9TGddQx2vx2A==}
|
resolution: {integrity: sha512-oKkx9z9Kwg40NtcIajF9uOXhxiyTZrrm9nmIJ4UjkU2IdHpd4QVLbCc/5hZN/y0C6qzi2Zlxyr9TGddQx2vx2A==}
|
||||||
engines: {node: '>=12.0.0'}
|
engines: {node: '>=12.0.0'}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
|
@ -2582,13 +2582,13 @@ packages:
|
||||||
optional: true
|
optional: true
|
||||||
dependencies:
|
dependencies:
|
||||||
'@babel/runtime': 7.21.0
|
'@babel/runtime': 7.21.0
|
||||||
'@mui/material': 5.13.6(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(@types/react@18.2.13)(react-dom@18.2.0)(react@18.2.0)
|
'@mui/material': 5.13.5(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(@types/react@18.2.13)(react-dom@18.2.0)(react@18.2.0)
|
||||||
'@types/react': 18.2.13
|
'@types/react': 18.2.13
|
||||||
react: 18.2.0
|
react: 18.2.0
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/@mui/material@5.13.6(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(@types/react@18.2.13)(react-dom@18.2.0)(react@18.2.0):
|
/@mui/material@5.13.5(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(@types/react@18.2.13)(react-dom@18.2.0)(react@18.2.0):
|
||||||
resolution: {integrity: sha512-/c2ZApeQm2sTYdQXjqEnldaBMBcUEiyu2VRS6bS39ZeNaAcCLBQbYocLR46R+f0S5dgpBzB0T4AsOABPOFYZ5Q==}
|
resolution: {integrity: sha512-eMay+Ue1OYXOFMQA5Aau7qbAa/kWHLAyi0McsbPTWssCbGehqkF6CIdPsfVGw6tlO+xPee1hUitphHJNL3xpOQ==}
|
||||||
engines: {node: '>=12.0.0'}
|
engines: {node: '>=12.0.0'}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
'@emotion/react': ^11.5.0
|
'@emotion/react': ^11.5.0
|
||||||
|
@ -2604,14 +2604,14 @@ packages:
|
||||||
'@types/react':
|
'@types/react':
|
||||||
optional: true
|
optional: true
|
||||||
dependencies:
|
dependencies:
|
||||||
'@babel/runtime': 7.22.5
|
'@babel/runtime': 7.21.0
|
||||||
'@emotion/react': 11.11.1(@types/react@18.2.13)(react@18.2.0)
|
'@emotion/react': 11.11.1(@types/react@18.2.13)(react@18.2.0)
|
||||||
'@emotion/styled': 11.11.0(@emotion/react@11.11.1)(@types/react@18.2.13)(react@18.2.0)
|
'@emotion/styled': 11.11.0(@emotion/react@11.11.1)(@types/react@18.2.13)(react@18.2.0)
|
||||||
'@mui/base': 5.0.0-beta.5(@types/react@18.2.13)(react-dom@18.2.0)(react@18.2.0)
|
'@mui/base': 5.0.0-beta.4(@types/react@18.2.13)(react-dom@18.2.0)(react@18.2.0)
|
||||||
'@mui/core-downloads-tracker': 5.13.4
|
'@mui/core-downloads-tracker': 5.13.4
|
||||||
'@mui/system': 5.13.6(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(@types/react@18.2.13)(react@18.2.0)
|
'@mui/system': 5.13.5(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(@types/react@18.2.13)(react@18.2.0)
|
||||||
'@mui/types': 7.2.4(@types/react@18.2.13)
|
'@mui/types': 7.2.4(@types/react@18.2.13)
|
||||||
'@mui/utils': 5.13.6(react@18.2.0)
|
'@mui/utils': 5.13.1(react@18.2.0)
|
||||||
'@types/react': 18.2.13
|
'@types/react': 18.2.13
|
||||||
'@types/react-transition-group': 4.4.6
|
'@types/react-transition-group': 4.4.6
|
||||||
clsx: 1.2.1
|
clsx: 1.2.1
|
||||||
|
@ -2634,7 +2634,7 @@ packages:
|
||||||
optional: true
|
optional: true
|
||||||
dependencies:
|
dependencies:
|
||||||
'@babel/runtime': 7.22.5
|
'@babel/runtime': 7.22.5
|
||||||
'@mui/utils': 5.13.6(react@18.2.0)
|
'@mui/utils': 5.13.1(react@18.2.0)
|
||||||
'@types/react': 18.2.13
|
'@types/react': 18.2.13
|
||||||
prop-types: 15.8.1
|
prop-types: 15.8.1
|
||||||
react: 18.2.0
|
react: 18.2.0
|
||||||
|
@ -2693,8 +2693,8 @@ packages:
|
||||||
react: 18.2.0
|
react: 18.2.0
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/@mui/system@5.13.6(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(@types/react@18.2.13)(react@18.2.0):
|
/@mui/system@5.13.5(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(@types/react@18.2.13)(react@18.2.0):
|
||||||
resolution: {integrity: sha512-G3Xr28uLqU3DyF6r2LQkHGw/ku4P0AHzlKVe7FGXOPl7X1u+hoe2xxj8Vdiq/69II/mh9OP21i38yBWgWb7WgQ==}
|
resolution: {integrity: sha512-n0gzUxoZ2ZHZgnExkh2Htvo9uW2oakofgPRQrDoa/GQOWyRD0NH9MDszBwOb6AAoXZb+OV5TE7I4LeZ/dzgHYA==}
|
||||||
engines: {node: '>=12.0.0'}
|
engines: {node: '>=12.0.0'}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
'@emotion/react': ^11.5.0
|
'@emotion/react': ^11.5.0
|
||||||
|
@ -2715,7 +2715,7 @@ packages:
|
||||||
'@mui/private-theming': 5.13.1(@types/react@18.2.13)(react@18.2.0)
|
'@mui/private-theming': 5.13.1(@types/react@18.2.13)(react@18.2.0)
|
||||||
'@mui/styled-engine': 5.13.2(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(react@18.2.0)
|
'@mui/styled-engine': 5.13.2(@emotion/react@11.11.1)(@emotion/styled@11.11.0)(react@18.2.0)
|
||||||
'@mui/types': 7.2.4(@types/react@18.2.13)
|
'@mui/types': 7.2.4(@types/react@18.2.13)
|
||||||
'@mui/utils': 5.13.6(react@18.2.0)
|
'@mui/utils': 5.13.1(react@18.2.0)
|
||||||
'@types/react': 18.2.13
|
'@types/react': 18.2.13
|
||||||
clsx: 1.2.1
|
clsx: 1.2.1
|
||||||
csstype: 3.1.2
|
csstype: 3.1.2
|
||||||
|
@ -2748,20 +2748,6 @@ packages:
|
||||||
react-is: 18.2.0
|
react-is: 18.2.0
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/@mui/utils@5.13.6(react@18.2.0):
|
|
||||||
resolution: {integrity: sha512-ggNlxl5NPSbp+kNcQLmSig6WVB0Id+4gOxhx644987v4fsji+CSXc+MFYLocFB/x4oHtzCUlSzbVHlJfP/fXoQ==}
|
|
||||||
engines: {node: '>=12.0.0'}
|
|
||||||
peerDependencies:
|
|
||||||
react: ^17.0.0 || ^18.0.0 || 18
|
|
||||||
dependencies:
|
|
||||||
'@babel/runtime': 7.22.5
|
|
||||||
'@types/prop-types': 15.7.5
|
|
||||||
'@types/react-is': 18.2.0
|
|
||||||
prop-types: 15.8.1
|
|
||||||
react: 18.2.0
|
|
||||||
react-is: 18.2.0
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/@nicolo-ribaudo/eslint-scope-5-internals@5.1.1-v1:
|
/@nicolo-ribaudo/eslint-scope-5-internals@5.1.1-v1:
|
||||||
resolution: {integrity: sha512-54/JRvkLIzzDWshCWfuhadfrfZVPiElY8Fcgmg1HroEly/EDSszzhBAsarCux+D/kOslTRquNzuyGSmUSTTHGg==}
|
resolution: {integrity: sha512-54/JRvkLIzzDWshCWfuhadfrfZVPiElY8Fcgmg1HroEly/EDSszzhBAsarCux+D/kOslTRquNzuyGSmUSTTHGg==}
|
||||||
dependencies:
|
dependencies:
|
||||||
|
@ -4579,7 +4565,6 @@ packages:
|
||||||
/esbuild@0.15.18:
|
/esbuild@0.15.18:
|
||||||
resolution: {integrity: sha512-x/R72SmW3sSFRm5zrrIjAhCeQSAWoni3CmHEqfQrZIQTM3lVCdehdwuIqaOtfC2slvpdlLa62GYoN8SxT23m6Q==}
|
resolution: {integrity: sha512-x/R72SmW3sSFRm5zrrIjAhCeQSAWoni3CmHEqfQrZIQTM3lVCdehdwuIqaOtfC2slvpdlLa62GYoN8SxT23m6Q==}
|
||||||
engines: {node: '>=12'}
|
engines: {node: '>=12'}
|
||||||
hasBin: true
|
|
||||||
requiresBuild: true
|
requiresBuild: true
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
'@esbuild/android-arm': 0.15.18
|
'@esbuild/android-arm': 0.15.18
|
||||||
|
@ -4609,7 +4594,6 @@ packages:
|
||||||
/esbuild@0.17.19:
|
/esbuild@0.17.19:
|
||||||
resolution: {integrity: sha512-XQ0jAPFkK/u3LcVRcvVHQcTIqD6E2H1fvZMA5dQPSOWb3suUbWbfbRf94pjc0bNzRYLfIrDRQXr7X+LHIm5oHw==}
|
resolution: {integrity: sha512-XQ0jAPFkK/u3LcVRcvVHQcTIqD6E2H1fvZMA5dQPSOWb3suUbWbfbRf94pjc0bNzRYLfIrDRQXr7X+LHIm5oHw==}
|
||||||
engines: {node: '>=12'}
|
engines: {node: '>=12'}
|
||||||
hasBin: true
|
|
||||||
requiresBuild: true
|
requiresBuild: true
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
'@esbuild/android-arm': 0.17.19
|
'@esbuild/android-arm': 0.17.19
|
||||||
|
@ -4636,34 +4620,33 @@ packages:
|
||||||
'@esbuild/win32-x64': 0.17.19
|
'@esbuild/win32-x64': 0.17.19
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/esbuild@0.18.6:
|
/esbuild@0.18.4:
|
||||||
resolution: {integrity: sha512-5QgxWaAhU/tPBpvkxUmnFv2YINHuZzjbk0LeUUnC2i3aJHjfi5yR49lgKgF7cb98bclOp/kans8M5TGbGFfJlQ==}
|
resolution: {integrity: sha512-9rxWV/Cb2DMUXfe9aUsYtqg0KTlw146ElFH22kYeK9KVV1qT082X4lpmiKsa12ePiCcIcB686TQJxaGAa9TFvA==}
|
||||||
engines: {node: '>=12'}
|
engines: {node: '>=12'}
|
||||||
hasBin: true
|
|
||||||
requiresBuild: true
|
requiresBuild: true
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
'@esbuild/android-arm': 0.18.6
|
'@esbuild/android-arm': 0.18.4
|
||||||
'@esbuild/android-arm64': 0.18.6
|
'@esbuild/android-arm64': 0.18.4
|
||||||
'@esbuild/android-x64': 0.18.6
|
'@esbuild/android-x64': 0.18.4
|
||||||
'@esbuild/darwin-arm64': 0.18.6
|
'@esbuild/darwin-arm64': 0.18.4
|
||||||
'@esbuild/darwin-x64': 0.18.6
|
'@esbuild/darwin-x64': 0.18.4
|
||||||
'@esbuild/freebsd-arm64': 0.18.6
|
'@esbuild/freebsd-arm64': 0.18.4
|
||||||
'@esbuild/freebsd-x64': 0.18.6
|
'@esbuild/freebsd-x64': 0.18.4
|
||||||
'@esbuild/linux-arm': 0.18.6
|
'@esbuild/linux-arm': 0.18.4
|
||||||
'@esbuild/linux-arm64': 0.18.6
|
'@esbuild/linux-arm64': 0.18.4
|
||||||
'@esbuild/linux-ia32': 0.18.6
|
'@esbuild/linux-ia32': 0.18.4
|
||||||
'@esbuild/linux-loong64': 0.18.6
|
'@esbuild/linux-loong64': 0.18.4
|
||||||
'@esbuild/linux-mips64el': 0.18.6
|
'@esbuild/linux-mips64el': 0.18.4
|
||||||
'@esbuild/linux-ppc64': 0.18.6
|
'@esbuild/linux-ppc64': 0.18.4
|
||||||
'@esbuild/linux-riscv64': 0.18.6
|
'@esbuild/linux-riscv64': 0.18.4
|
||||||
'@esbuild/linux-s390x': 0.18.6
|
'@esbuild/linux-s390x': 0.18.4
|
||||||
'@esbuild/linux-x64': 0.18.6
|
'@esbuild/linux-x64': 0.18.4
|
||||||
'@esbuild/netbsd-x64': 0.18.6
|
'@esbuild/netbsd-x64': 0.18.4
|
||||||
'@esbuild/openbsd-x64': 0.18.6
|
'@esbuild/openbsd-x64': 0.18.4
|
||||||
'@esbuild/sunos-x64': 0.18.6
|
'@esbuild/sunos-x64': 0.18.4
|
||||||
'@esbuild/win32-arm64': 0.18.6
|
'@esbuild/win32-arm64': 0.18.4
|
||||||
'@esbuild/win32-ia32': 0.18.6
|
'@esbuild/win32-ia32': 0.18.4
|
||||||
'@esbuild/win32-x64': 0.18.6
|
'@esbuild/win32-x64': 0.18.4
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/escalade@3.1.1:
|
/escalade@3.1.1:
|
||||||
|
@ -5604,8 +5587,8 @@ packages:
|
||||||
- encoding
|
- encoding
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/i18next@23.2.3:
|
/i18next@23.1.0:
|
||||||
resolution: {integrity: sha512-5spO7L0rNmW0jFuNhz+gfirlFt1anle4mTy4+gFkgsH0+T3R5++4oncBrzeKa7v8pweRyGBoGmOpboqlxovg6A==}
|
resolution: {integrity: sha512-CObNPofJpw7zGVGYLd58mtMZUF+NZQl9czYMihbJkStjX+Nlu9kC3PHiC6uE1niP3qxP/3ocLXIBc2zqbAb1dg==}
|
||||||
dependencies:
|
dependencies:
|
||||||
'@babel/runtime': 7.22.5
|
'@babel/runtime': 7.22.5
|
||||||
dev: false
|
dev: false
|
||||||
|
@ -6813,10 +6796,10 @@ packages:
|
||||||
react: 18.2.0
|
react: 18.2.0
|
||||||
scheduler: 0.23.0
|
scheduler: 0.23.0
|
||||||
|
|
||||||
/react-i18next@13.0.1(i18next@23.2.3)(react-dom@18.2.0)(react@18.2.0):
|
/react-i18next@13.0.0(i18next@23.1.0)(react-dom@18.2.0)(react@18.2.0):
|
||||||
resolution: {integrity: sha512-gMO6N2GfSfuH7xlHSsZ/mZf+Py9bLm/+EDKIn5fNTuDTjcCcwmMU5UEuGCDk5mdfivbo7ySyYXBN7B9tbGUxiA==}
|
resolution: {integrity: sha512-qRFbrSgynsBSjfnSTb/Um3mw9uPjOfDi4Iq2rMCuzfsRsYGdkEdyCr0i+T0bR0bG6xwULvK4k1oRVLLd7ZDBVw==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
i18next: '>= 23.2.3'
|
i18next: '>= 23.0.1'
|
||||||
react: '>= 16.8.0 || 18'
|
react: '>= 16.8.0 || 18'
|
||||||
react-dom: '*'
|
react-dom: '*'
|
||||||
react-native: '*'
|
react-native: '*'
|
||||||
|
@ -6828,7 +6811,7 @@ packages:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@babel/runtime': 7.22.5
|
'@babel/runtime': 7.22.5
|
||||||
html-parse-stringify: 3.0.1
|
html-parse-stringify: 3.0.1
|
||||||
i18next: 23.2.3
|
i18next: 23.1.0
|
||||||
react: 18.2.0
|
react: 18.2.0
|
||||||
react-dom: 18.2.0(react@18.2.0)
|
react-dom: 18.2.0(react@18.2.0)
|
||||||
dev: false
|
dev: false
|
||||||
|
|
Loading…
Reference in New Issue