diff --git a/authserver/.gitignore b/authserver/.gitignore
index 6097006..eca0741 100644
--- a/authserver/.gitignore
+++ b/authserver/.gitignore
@@ -5,7 +5,7 @@
.DS_Store
*.tar
bin/
-/server
+server
web/node_modules/
web/dist/
certs/
diff --git a/authserver/cmd/server/main.go b/authserver/cmd/server/main.go
deleted file mode 100644
index 7ad3580..0000000
--- a/authserver/cmd/server/main.go
+++ /dev/null
@@ -1,37 +0,0 @@
-package main
-
-import (
- "log"
-
- "authserver/internal/config"
- "authserver/internal/database"
- "authserver/internal/router"
-)
-
-func main() {
- cfg := config.Load()
-
- db, err := database.Open(cfg.MySQLDSN)
- if err != nil {
- log.Fatalf("open database: %v", err)
- }
-
- if cfg.AutoMigrate {
- if err := database.AutoMigrate(db); err != nil {
- log.Fatalf("auto migrate: %v", err)
- }
- }
- if err := database.SeedDefaults(db, cfg); err != nil {
- log.Fatalf("seed defaults: %v", err)
- }
-
- r := router.New(router.Dependencies{
- Config: cfg,
- DB: db,
- })
-
- log.Printf("authserver listening on %s", cfg.HTTPAddr)
- if err := r.Run(cfg.HTTPAddr); err != nil {
- log.Fatalf("run server: %v", err)
- }
-}
diff --git a/authserver/internal/handler/saml.go b/authserver/internal/handler/saml.go
index 0ca7f23..a90818d 100644
--- a/authserver/internal/handler/saml.go
+++ b/authserver/internal/handler/saml.go
@@ -97,15 +97,15 @@ func (h *SAMLHandler) ACS(c *gin.Context) {
func ssoRedirectURL(relayState, token string) string {
target := strings.TrimSpace(relayState)
- if target == "" || !strings.HasPrefix(target, "/") {
- target = "/"
+ if target == "" || !strings.HasPrefix(target, "/auth/") {
+ target = "/auth/"
}
if strings.HasPrefix(target, "//") {
- target = "/"
+ target = "/auth/"
}
parsed, err := url.Parse(target)
if err != nil || parsed.IsAbs() {
- parsed = &url.URL{Path: "/"}
+ parsed = &url.URL{Path: "/auth/"}
}
values := parsed.Query()
values.Set("sso_token", token)
diff --git a/authserver/k8s/nginx.yaml b/authserver/k8s/nginx.yaml
deleted file mode 100644
index fae0081..0000000
--- a/authserver/k8s/nginx.yaml
+++ /dev/null
@@ -1,148 +0,0 @@
-apiVersion: v1
-kind: ConfigMap
-metadata:
- name: authserver-nginx-conf
- namespace: authserver
-data:
- default.conf.template: |
- server {
- listen 80;
- server_name _;
-
- client_max_body_size 10m;
-
- location = /healthz {
- proxy_pass ${AUTHSERVER_BACKEND_UPSTREAM};
- proxy_http_version 1.1;
- proxy_set_header Host $host;
- proxy_set_header X-Real-IP $remote_addr;
- proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
- proxy_set_header X-Forwarded-Proto $scheme;
- }
-
- location = /readyz {
- proxy_pass ${AUTHSERVER_BACKEND_UPSTREAM};
- proxy_http_version 1.1;
- proxy_set_header Host $host;
- proxy_set_header X-Real-IP $remote_addr;
- proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
- proxy_set_header X-Forwarded-Proto $scheme;
- }
-
- location /auth/api/ {
- proxy_pass ${AUTHSERVER_BACKEND_UPSTREAM};
- proxy_http_version 1.1;
- proxy_set_header Host $host;
- proxy_set_header X-Real-IP $remote_addr;
- proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
- proxy_set_header X-Forwarded-Proto $scheme;
- proxy_connect_timeout 5s;
- proxy_send_timeout 60s;
- proxy_read_timeout 60s;
- }
-
- location /auth/oauth/ {
- proxy_pass ${AUTHSERVER_BACKEND_UPSTREAM};
- proxy_http_version 1.1;
- proxy_set_header Host $host;
- proxy_set_header X-Real-IP $remote_addr;
- proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
- proxy_set_header X-Forwarded-Proto $scheme;
- proxy_connect_timeout 5s;
- proxy_send_timeout 60s;
- proxy_read_timeout 60s;
- }
-
- location /auth/.well-known/ {
- proxy_pass ${AUTHSERVER_BACKEND_UPSTREAM};
- proxy_http_version 1.1;
- proxy_set_header Host $host;
- proxy_set_header X-Real-IP $remote_addr;
- proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
- proxy_set_header X-Forwarded-Proto $scheme;
- proxy_connect_timeout 5s;
- proxy_send_timeout 60s;
- proxy_read_timeout 60s;
- }
-
- location /internal/clouddm/ {
- proxy_pass ${CLOUDDM_UPSTREAM}/;
- proxy_http_version 1.1;
- proxy_set_header Host ${CLOUDDM_PUBLIC_HOST};
- proxy_set_header X-Real-IP $remote_addr;
- proxy_set_header X-Forwarded-Host ${CLOUDDM_PUBLIC_HOST};
- proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
- proxy_set_header X-Forwarded-Proto http;
- proxy_connect_timeout 5s;
- proxy_send_timeout 60s;
- proxy_read_timeout 60s;
- }
-
- location / {
- return 404;
- }
- }
----
-apiVersion: apps/v1
-kind: Deployment
-metadata:
- name: authserver-nginx
- namespace: authserver
-spec:
- replicas: 1
- selector:
- matchLabels:
- app: authserver-nginx
- template:
- metadata:
- labels:
- app: authserver-nginx
- spec:
- containers:
- - name: nginx
- image: nginx:1.29-alpine
- imagePullPolicy: IfNotPresent
- ports:
- - containerPort: 80
- env:
- - name: AUTHSERVER_BACKEND_UPSTREAM
- value: http://authserver-backend:8083
- - name: CLOUDDM_UPSTREAM
- value: http://open-cdm.db.svc.cluster.local:8222
- - name: CLOUDDM_PUBLIC_HOST
- value: 218.11.5.223:30009
- volumeMounts:
- - name: nginx-conf
- mountPath: /etc/nginx/templates/default.conf.template
- subPath: default.conf.template
- readinessProbe:
- httpGet:
- path: /readyz
- port: 80
- initialDelaySeconds: 5
- periodSeconds: 10
- livenessProbe:
- httpGet:
- path: /healthz
- port: 80
- initialDelaySeconds: 10
- periodSeconds: 20
- volumes:
- - name: nginx-conf
- configMap:
- name: authserver-nginx-conf
----
-apiVersion: v1
-kind: Service
-metadata:
- name: authserver-nginx
- namespace: authserver
-spec:
- type: NodePort
- selector:
- app: authserver-nginx
- ports:
- - name: http
- port: 80
- targetPort: 80
- nodePort: 30080
diff --git a/authserver/web/.dockerignore b/authserver/web/.dockerignore
new file mode 100644
index 0000000..a7e5733
--- /dev/null
+++ b/authserver/web/.dockerignore
@@ -0,0 +1,4 @@
+node_modules/
+dist/
+.DS_Store
+
diff --git a/authserver/web/Dockerfile b/authserver/web/Dockerfile
new file mode 100644
index 0000000..debcaaf
--- /dev/null
+++ b/authserver/web/Dockerfile
@@ -0,0 +1,16 @@
+FROM node:14-alpine AS builder
+
+WORKDIR /app
+
+COPY package*.json ./
+RUN npm install --no-audit --no-fund
+
+COPY . .
+RUN npm run build
+
+FROM nginx:1.29-alpine
+
+COPY nginx.conf /etc/nginx/conf.d/default.conf
+COPY --from=builder /app/dist /usr/share/nginx/html/auth
+
+EXPOSE 80
diff --git a/authserver/web/index.html b/authserver/web/index.html
new file mode 100644
index 0000000..f469a73
--- /dev/null
+++ b/authserver/web/index.html
@@ -0,0 +1,12 @@
+
+
+
+
+
+ AuthServer
+
+
+
+
+
+
diff --git a/authserver/web/nginx.conf b/authserver/web/nginx.conf
new file mode 100644
index 0000000..caaae48
--- /dev/null
+++ b/authserver/web/nginx.conf
@@ -0,0 +1,90 @@
+server {
+ listen 80;
+ server_name _;
+
+ client_max_body_size 10m;
+
+ root /usr/share/nginx/html;
+ index index.html;
+
+ location = / {
+ return 302 /auth/;
+ }
+
+ location = /healthz {
+ proxy_pass http://authserver-backend:8083;
+ proxy_http_version 1.1;
+ proxy_set_header Host $host;
+ proxy_set_header X-Real-IP $remote_addr;
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+ proxy_set_header X-Forwarded-Proto $scheme;
+ }
+
+ location = /readyz {
+ proxy_pass http://authserver-backend:8083;
+ proxy_http_version 1.1;
+ proxy_set_header Host $host;
+ proxy_set_header X-Real-IP $remote_addr;
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+ proxy_set_header X-Forwarded-Proto $scheme;
+ }
+
+ location /auth/api/ {
+ proxy_pass http://authserver-backend:8083;
+ proxy_http_version 1.1;
+ proxy_set_header Host $host;
+ proxy_set_header X-Real-IP $remote_addr;
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+ proxy_set_header X-Forwarded-Proto $scheme;
+ proxy_connect_timeout 5s;
+ proxy_send_timeout 60s;
+ proxy_read_timeout 60s;
+ }
+
+ location /auth/oauth/ {
+ proxy_pass http://authserver-backend:8083;
+ proxy_http_version 1.1;
+ proxy_set_header Host $host;
+ proxy_set_header X-Real-IP $remote_addr;
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+ proxy_set_header X-Forwarded-Proto $scheme;
+ proxy_connect_timeout 5s;
+ proxy_send_timeout 60s;
+ proxy_read_timeout 60s;
+ }
+
+ location /auth/.well-known/ {
+ proxy_pass http://authserver-backend:8083;
+ proxy_http_version 1.1;
+ proxy_set_header Host $host;
+ proxy_set_header X-Real-IP $remote_addr;
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+ proxy_set_header X-Forwarded-Proto $scheme;
+ proxy_connect_timeout 5s;
+ proxy_send_timeout 60s;
+ proxy_read_timeout 60s;
+ }
+
+ location /internal/clouddm/ {
+ proxy_pass http://open-cdm.db.svc.cluster.local:8222/;
+ proxy_http_version 1.1;
+ proxy_set_header Host 218.11.5.223:30009;
+ proxy_set_header X-Real-IP $remote_addr;
+ proxy_set_header X-Forwarded-Host 218.11.5.223:30009;
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+ proxy_set_header X-Forwarded-Proto http;
+ proxy_connect_timeout 5s;
+ proxy_send_timeout 60s;
+ proxy_read_timeout 60s;
+ }
+
+ location /auth/ {
+ try_files $uri $uri/ /auth/index.html;
+ }
+
+ location ~* \.(js|css|png|jpg|jpeg|gif|svg|ico|woff2?)$ {
+ expires 7d;
+ add_header Cache-Control "public, max-age=604800";
+ try_files $uri =404;
+ }
+}
diff --git a/authserver/web/package-lock.json b/authserver/web/package-lock.json
new file mode 100644
index 0000000..6c2df8d
--- /dev/null
+++ b/authserver/web/package-lock.json
@@ -0,0 +1,379 @@
+{
+ "name": "authserver-web",
+ "version": "0.1.0",
+ "lockfileVersion": 1,
+ "requires": true,
+ "dependencies": {
+ "@babel/helper-string-parser": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz",
+ "integrity": "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw=="
+ },
+ "@babel/helper-validator-identifier": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz",
+ "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg=="
+ },
+ "@babel/parser": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.7.tgz",
+ "integrity": "sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==",
+ "requires": {
+ "@babel/types": "^7.29.7"
+ }
+ },
+ "@babel/types": {
+ "version": "7.29.7",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.7.tgz",
+ "integrity": "sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==",
+ "requires": {
+ "@babel/helper-string-parser": "^7.29.7",
+ "@babel/helper-validator-identifier": "^7.29.7"
+ }
+ },
+ "@esbuild/android-arm": {
+ "version": "0.18.20",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.20.tgz",
+ "integrity": "sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==",
+ "optional": true
+ },
+ "@esbuild/android-arm64": {
+ "version": "0.18.20",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.18.20.tgz",
+ "integrity": "sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==",
+ "optional": true
+ },
+ "@esbuild/android-x64": {
+ "version": "0.18.20",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.18.20.tgz",
+ "integrity": "sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==",
+ "optional": true
+ },
+ "@esbuild/darwin-arm64": {
+ "version": "0.18.20",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.18.20.tgz",
+ "integrity": "sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==",
+ "optional": true
+ },
+ "@esbuild/darwin-x64": {
+ "version": "0.18.20",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.18.20.tgz",
+ "integrity": "sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==",
+ "optional": true
+ },
+ "@esbuild/freebsd-arm64": {
+ "version": "0.18.20",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.20.tgz",
+ "integrity": "sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==",
+ "optional": true
+ },
+ "@esbuild/freebsd-x64": {
+ "version": "0.18.20",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.18.20.tgz",
+ "integrity": "sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==",
+ "optional": true
+ },
+ "@esbuild/linux-arm": {
+ "version": "0.18.20",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.18.20.tgz",
+ "integrity": "sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==",
+ "optional": true
+ },
+ "@esbuild/linux-arm64": {
+ "version": "0.18.20",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.18.20.tgz",
+ "integrity": "sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==",
+ "optional": true
+ },
+ "@esbuild/linux-ia32": {
+ "version": "0.18.20",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.18.20.tgz",
+ "integrity": "sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==",
+ "optional": true
+ },
+ "@esbuild/linux-loong64": {
+ "version": "0.18.20",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.18.20.tgz",
+ "integrity": "sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==",
+ "optional": true
+ },
+ "@esbuild/linux-mips64el": {
+ "version": "0.18.20",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.18.20.tgz",
+ "integrity": "sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==",
+ "optional": true
+ },
+ "@esbuild/linux-ppc64": {
+ "version": "0.18.20",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.18.20.tgz",
+ "integrity": "sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==",
+ "optional": true
+ },
+ "@esbuild/linux-riscv64": {
+ "version": "0.18.20",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.18.20.tgz",
+ "integrity": "sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==",
+ "optional": true
+ },
+ "@esbuild/linux-s390x": {
+ "version": "0.18.20",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.18.20.tgz",
+ "integrity": "sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==",
+ "optional": true
+ },
+ "@esbuild/linux-x64": {
+ "version": "0.18.20",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.18.20.tgz",
+ "integrity": "sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==",
+ "optional": true
+ },
+ "@esbuild/netbsd-x64": {
+ "version": "0.18.20",
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.18.20.tgz",
+ "integrity": "sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==",
+ "optional": true
+ },
+ "@esbuild/openbsd-x64": {
+ "version": "0.18.20",
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.18.20.tgz",
+ "integrity": "sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==",
+ "optional": true
+ },
+ "@esbuild/sunos-x64": {
+ "version": "0.18.20",
+ "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.18.20.tgz",
+ "integrity": "sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==",
+ "optional": true
+ },
+ "@esbuild/win32-arm64": {
+ "version": "0.18.20",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.18.20.tgz",
+ "integrity": "sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==",
+ "optional": true
+ },
+ "@esbuild/win32-ia32": {
+ "version": "0.18.20",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.18.20.tgz",
+ "integrity": "sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==",
+ "optional": true
+ },
+ "@esbuild/win32-x64": {
+ "version": "0.18.20",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.18.20.tgz",
+ "integrity": "sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==",
+ "optional": true
+ },
+ "@jridgewell/sourcemap-codec": {
+ "version": "1.5.5",
+ "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz",
+ "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og=="
+ },
+ "@vitejs/plugin-vue": {
+ "version": "4.6.2",
+ "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-4.6.2.tgz",
+ "integrity": "sha512-kqf7SGFoG+80aZG6Pf+gsZIVvGSCKE98JbiWqcCV9cThtg91Jav0yvYFC9Zb+jKetNGF6ZKeoaxgZfND21fWKw=="
+ },
+ "@vue/compiler-core": {
+ "version": "3.5.17",
+ "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.17.tgz",
+ "integrity": "sha512-Xe+AittLbAyV0pabcN7cP7/BenRBNcteM4aSDCtRvGw0d9OL+HG1u/XHLY/kt1q4fyMeZYXyIYrsHuPSiDPosA==",
+ "requires": {
+ "@babel/parser": "^7.27.5",
+ "@vue/shared": "3.5.17",
+ "entities": "^4.5.0",
+ "estree-walker": "^2.0.2",
+ "source-map-js": "^1.2.1"
+ }
+ },
+ "@vue/compiler-dom": {
+ "version": "3.5.17",
+ "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.17.tgz",
+ "integrity": "sha512-+2UgfLKoaNLhgfhV5Ihnk6wB4ljyW1/7wUIog2puUqajiC29Lp5R/IKDdkebh9jTbTogTbsgB+OY9cEWzG95JQ==",
+ "requires": {
+ "@vue/compiler-core": "3.5.17",
+ "@vue/shared": "3.5.17"
+ }
+ },
+ "@vue/compiler-sfc": {
+ "version": "3.5.17",
+ "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.17.tgz",
+ "integrity": "sha512-rQQxbRJMgTqwRugtjw0cnyQv9cP4/4BxWfTdRBkqsTfLOHWykLzbOc3C4GGzAmdMDxhzU/1Ija5bTjMVrddqww==",
+ "requires": {
+ "@babel/parser": "^7.27.5",
+ "@vue/compiler-core": "3.5.17",
+ "@vue/compiler-dom": "3.5.17",
+ "@vue/compiler-ssr": "3.5.17",
+ "@vue/shared": "3.5.17",
+ "estree-walker": "^2.0.2",
+ "magic-string": "^0.30.17",
+ "postcss": "^8.5.6",
+ "source-map-js": "^1.2.1"
+ }
+ },
+ "@vue/compiler-ssr": {
+ "version": "3.5.17",
+ "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.17.tgz",
+ "integrity": "sha512-hkDbA0Q20ZzGgpj5uZjb9rBzQtIHLS78mMilwrlpWk2Ep37DYntUz0PonQ6kr113vfOEdM+zTBuJDaceNIW0tQ==",
+ "requires": {
+ "@vue/compiler-dom": "3.5.17",
+ "@vue/shared": "3.5.17"
+ }
+ },
+ "@vue/reactivity": {
+ "version": "3.5.17",
+ "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.17.tgz",
+ "integrity": "sha512-l/rmw2STIscWi7SNJp708FK4Kofs97zc/5aEPQh4bOsReD/8ICuBcEmS7KGwDj5ODQLYWVN2lNibKJL1z5b+Lw==",
+ "requires": {
+ "@vue/shared": "3.5.17"
+ }
+ },
+ "@vue/runtime-core": {
+ "version": "3.5.17",
+ "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.17.tgz",
+ "integrity": "sha512-QQLXa20dHg1R0ri4bjKeGFKEkJA7MMBxrKo2G+gJikmumRS7PTD4BOU9FKrDQWMKowz7frJJGqBffYMgQYS96Q==",
+ "requires": {
+ "@vue/reactivity": "3.5.17",
+ "@vue/shared": "3.5.17"
+ }
+ },
+ "@vue/runtime-dom": {
+ "version": "3.5.17",
+ "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.17.tgz",
+ "integrity": "sha512-8El0M60TcwZ1QMz4/os2MdlQECgGoVHPuLnQBU3m9h3gdNRW9xRmI8iLS4t/22OQlOE6aJvNNlBiCzPHur4H9g==",
+ "requires": {
+ "@vue/reactivity": "3.5.17",
+ "@vue/runtime-core": "3.5.17",
+ "@vue/shared": "3.5.17",
+ "csstype": "^3.1.3"
+ }
+ },
+ "@vue/server-renderer": {
+ "version": "3.5.17",
+ "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.17.tgz",
+ "integrity": "sha512-BOHhm8HalujY6lmC3DbqF6uXN/K00uWiEeF22LfEsm9Q93XeJ/plHTepGwf6tqFcF7GA5oGSSAAUock3VvzaCA==",
+ "requires": {
+ "@vue/compiler-ssr": "3.5.17",
+ "@vue/shared": "3.5.17"
+ }
+ },
+ "@vue/shared": {
+ "version": "3.5.17",
+ "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.17.tgz",
+ "integrity": "sha512-CabR+UN630VnsJO/jHWYBC1YVXyMq94KKp6iF5MQgZJs5I8cmjw6oVMO1oDbtBkENSHSSn/UadWlW/OAgdmKrg=="
+ },
+ "csstype": {
+ "version": "3.2.3",
+ "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz",
+ "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ=="
+ },
+ "entities": {
+ "version": "4.5.0",
+ "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
+ "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw=="
+ },
+ "esbuild": {
+ "version": "0.18.20",
+ "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.20.tgz",
+ "integrity": "sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==",
+ "requires": {
+ "@esbuild/android-arm": "0.18.20",
+ "@esbuild/android-arm64": "0.18.20",
+ "@esbuild/android-x64": "0.18.20",
+ "@esbuild/darwin-arm64": "0.18.20",
+ "@esbuild/darwin-x64": "0.18.20",
+ "@esbuild/freebsd-arm64": "0.18.20",
+ "@esbuild/freebsd-x64": "0.18.20",
+ "@esbuild/linux-arm": "0.18.20",
+ "@esbuild/linux-arm64": "0.18.20",
+ "@esbuild/linux-ia32": "0.18.20",
+ "@esbuild/linux-loong64": "0.18.20",
+ "@esbuild/linux-mips64el": "0.18.20",
+ "@esbuild/linux-ppc64": "0.18.20",
+ "@esbuild/linux-riscv64": "0.18.20",
+ "@esbuild/linux-s390x": "0.18.20",
+ "@esbuild/linux-x64": "0.18.20",
+ "@esbuild/netbsd-x64": "0.18.20",
+ "@esbuild/openbsd-x64": "0.18.20",
+ "@esbuild/sunos-x64": "0.18.20",
+ "@esbuild/win32-arm64": "0.18.20",
+ "@esbuild/win32-ia32": "0.18.20",
+ "@esbuild/win32-x64": "0.18.20"
+ }
+ },
+ "estree-walker": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz",
+ "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w=="
+ },
+ "fsevents": {
+ "version": "2.3.3",
+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
+ "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
+ "optional": true
+ },
+ "magic-string": {
+ "version": "0.30.21",
+ "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz",
+ "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==",
+ "requires": {
+ "@jridgewell/sourcemap-codec": "^1.5.5"
+ }
+ },
+ "nanoid": {
+ "version": "3.3.16",
+ "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.16.tgz",
+ "integrity": "sha512-bzlKTyNJ7+LdGIIwy8ijFpIqEQIvafahV7eYykJ8Cvh42EdJeODoJ6gUJXpQJvej1BddH8OqTXZNE/KfbWAu8Q=="
+ },
+ "picocolors": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
+ "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="
+ },
+ "postcss": {
+ "version": "8.5.18",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.18.tgz",
+ "integrity": "sha512-xdB1oSLHbz1vRWgCDalrCqEFTWzFlhqFC5tIHLMOSUIjhm3XXQ1qrFy8S/ESr1JYRRXqM3c1QFiMZUJdUTqyMQ==",
+ "requires": {
+ "nanoid": "^3.3.12",
+ "picocolors": "^1.1.1",
+ "source-map-js": "^1.2.1"
+ }
+ },
+ "rollup": {
+ "version": "3.30.0",
+ "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.30.0.tgz",
+ "integrity": "sha512-kQvGasUgN+AlWGliFn2POSajRQEsULVYFGTvOZmK06d7vCD+YhZztt70kGk3qaeAXeWYL5eO7zx+rAubBc55eA==",
+ "requires": {
+ "fsevents": "~2.3.2"
+ }
+ },
+ "source-map-js": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
+ "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="
+ },
+ "vite": {
+ "version": "4.5.3",
+ "resolved": "https://registry.npmjs.org/vite/-/vite-4.5.3.tgz",
+ "integrity": "sha512-kQL23kMeX92v3ph7IauVkXkikdDRsYMGTVl5KY2E9OY4ONLvkHf04MDTbnfo6NKxZiDLWzVpP5oTa8hQD8U3dg==",
+ "requires": {
+ "esbuild": "^0.18.10",
+ "fsevents": "~2.3.2",
+ "postcss": "^8.4.27",
+ "rollup": "^3.27.1"
+ }
+ },
+ "vue": {
+ "version": "3.5.17",
+ "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.17.tgz",
+ "integrity": "sha512-LbHV3xPN9BeljML+Xctq4lbz2lVHCR6DtbpTf5XIO6gugpXUN49j2QQPcMj086r9+AkJ0FfUT8xjulKKBkkr9g==",
+ "requires": {
+ "@vue/compiler-dom": "3.5.17",
+ "@vue/compiler-sfc": "3.5.17",
+ "@vue/runtime-dom": "3.5.17",
+ "@vue/server-renderer": "3.5.17",
+ "@vue/shared": "3.5.17"
+ }
+ }
+ }
+}
diff --git a/authserver/web/package.json b/authserver/web/package.json
new file mode 100644
index 0000000..3f7d557
--- /dev/null
+++ b/authserver/web/package.json
@@ -0,0 +1,20 @@
+{
+ "name": "authserver-web",
+ "version": "0.1.0",
+ "private": true,
+ "type": "module",
+ "engines": {
+ "node": ">=14.18.0"
+ },
+ "scripts": {
+ "dev": "vite --host 0.0.0.0",
+ "build": "vite build",
+ "preview": "vite preview --host 0.0.0.0"
+ },
+ "dependencies": {
+ "@vitejs/plugin-vue": "4.6.2",
+ "vite": "4.5.3",
+ "vue": "3.5.17"
+ },
+ "devDependencies": {}
+}
diff --git a/authserver/web/src/App.vue b/authserver/web/src/App.vue
new file mode 100644
index 0000000..be8f366
--- /dev/null
+++ b/authserver/web/src/App.vue
@@ -0,0 +1,219 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ message }}
+
+
+
diff --git a/authserver/web/src/main.js b/authserver/web/src/main.js
new file mode 100644
index 0000000..2425c0f
--- /dev/null
+++ b/authserver/web/src/main.js
@@ -0,0 +1,5 @@
+import { createApp } from 'vue'
+import './style.css'
+import App from './App.vue'
+
+createApp(App).mount('#app')
diff --git a/authserver/web/src/style.css b/authserver/web/src/style.css
new file mode 100644
index 0000000..9283195
--- /dev/null
+++ b/authserver/web/src/style.css
@@ -0,0 +1,206 @@
+* {
+ box-sizing: border-box;
+}
+
+body {
+ margin: 0;
+ min-width: 320px;
+ min-height: 100vh;
+ color: #172033;
+ background: #f5f7fb;
+ font-family:
+ Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI",
+ sans-serif;
+}
+
+button,
+input {
+ font: inherit;
+}
+
+button {
+ min-height: 36px;
+ border: 1px solid #cfd7e6;
+ border-radius: 6px;
+ background: #ffffff;
+ color: #172033;
+ cursor: pointer;
+}
+
+button:disabled {
+ cursor: not-allowed;
+ opacity: 0.55;
+}
+
+input {
+ width: 100%;
+ min-height: 36px;
+ border: 1px solid #cfd7e6;
+ border-radius: 6px;
+ padding: 0 10px;
+ background: #ffffff;
+ color: #172033;
+}
+
+h1,
+p {
+ margin: 0;
+}
+
+h1 {
+ font-size: 22px;
+ line-height: 1.2;
+}
+
+.login-page {
+ min-height: 100vh;
+ display: grid;
+ place-items: center;
+ padding: 24px;
+}
+
+.login-panel {
+ width: min(420px, 100%);
+ display: grid;
+ gap: 22px;
+ border: 1px solid #dbe3ef;
+ border-radius: 8px;
+ padding: 28px;
+ background: #ffffff;
+ box-shadow: 0 18px 50px rgb(43 57 84 / 10%);
+}
+
+.primary {
+ border-color: #1b64d8;
+ background: #1b64d8;
+ color: #ffffff;
+ font-weight: 650;
+}
+
+.secondary {
+ padding: 0 14px;
+ border-color: #b8c5d9;
+ background: #ffffff;
+}
+
+.eyebrow {
+ margin-bottom: 6px;
+ color: #526174;
+ font-size: 12px;
+ font-weight: 700;
+ letter-spacing: 0;
+ text-transform: uppercase;
+}
+
+.message {
+ margin-top: 4px;
+ color: #31516f;
+ font-size: 13px;
+}
+
+.app-page {
+ min-height: 100vh;
+ display: grid;
+ grid-template-rows: auto 1fr;
+ background:
+ linear-gradient(135deg, rgb(22 82 170 / 8%), transparent 42%),
+ #f5f7fb;
+}
+
+.app-header {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ gap: 16px;
+ padding: 22px 28px;
+ border-bottom: 1px solid #dbe3ef;
+ background: rgb(255 255 255 / 86%);
+ backdrop-filter: blur(10px);
+}
+
+.app-main {
+ display: grid;
+ grid-template-columns: repeat(auto-fit, minmax(280px, 360px));
+ justify-content: center;
+ align-items: center;
+ gap: 18px;
+ padding: 32px 20px;
+}
+
+.app-button {
+ width: min(280px, 78vw);
+ aspect-ratio: 1;
+ display: grid;
+ place-items: center;
+ align-content: center;
+ gap: 18px;
+ border-color: #cfdaf0;
+ border-radius: 8px;
+ background: #ffffff;
+ box-shadow: 0 18px 50px rgb(43 57 84 / 12%);
+}
+
+.app-button:hover:not(:disabled),
+.app-button:focus-visible {
+ border-color: #1b64d8;
+ box-shadow: 0 22px 60px rgb(27 100 216 / 18%);
+ outline: none;
+}
+
+.app-icon {
+ width: 112px;
+ height: 112px;
+ display: grid;
+ place-items: center;
+ border-radius: 28px;
+ color: #ffffff;
+ font-size: 64px;
+ font-weight: 800;
+ line-height: 1;
+}
+
+.wayen-icon {
+ background: #1b64d8;
+}
+
+.clouddm-icon {
+ background: #0f7b6c;
+}
+
+.app-title {
+ color: #172033;
+ font-size: 22px;
+ font-weight: 750;
+}
+
+.user-block {
+ display: flex;
+ align-items: center;
+ gap: 12px;
+ color: #526174;
+ font-size: 14px;
+}
+
+@media (max-width: 560px) {
+ .app-header {
+ align-items: flex-start;
+ flex-direction: column;
+ padding: 18px 20px;
+ }
+
+ .user-block {
+ width: 100%;
+ justify-content: space-between;
+ }
+
+ .app-icon {
+ width: 92px;
+ height: 92px;
+ border-radius: 22px;
+ font-size: 52px;
+ }
+
+ .app-main {
+ grid-template-columns: 1fr;
+ }
+}
diff --git a/authserver/web/vite.config.js b/authserver/web/vite.config.js
new file mode 100644
index 0000000..6cb45ed
--- /dev/null
+++ b/authserver/web/vite.config.js
@@ -0,0 +1,15 @@
+import { defineConfig } from 'vite'
+import vue from '@vitejs/plugin-vue'
+
+export default defineConfig({
+ base: '/auth/',
+ plugins: [vue()],
+ server: {
+ port: 5173,
+ proxy: {
+ '/auth/api': 'http://127.0.0.1:8083',
+ '/healthz': 'http://127.0.0.1:8083',
+ '/readyz': 'http://127.0.0.1:8083',
+ },
+ },
+})