[FEATURE] Add API docs and swagger-ui (#1544)
* [FEATURE] Add API docs and swagger-ui This change will serve out swagger-ui at the `/api/` root path. * Update descriptions and summaries in API spec * Utilise frontend assets from unit testing for Docker build steps * Fix tag for /api/user/* endpoints * Fix response schema for /api/user/info/2fa_method * Template and inject the session name during runtime into swagger-ui This change also factorises and renames index.go into template.go, this can now be generically utilised to template any file. * Fix integration tests * Add U2F endpoints * Change swagger directory to api This change is to more closely conform to the golang-standards project layout. * Add authentication for u2f endpoints * Modify u2f endpoint descriptions * Rename and fix u2f 2fa sign endpoints * Fix request body for /api/secondfactor/u2f/sign endpoint Co-authored-by: James Elliott <james-d-elliott@users.noreply.github.com>pull/1557/head^2
parent
689fd7cb95
commit
3487fd392e
|
@ -14,6 +14,12 @@ if [[ $BUILDKITE_LABEL =~ ":selenium:" ]]; then
|
||||||
docker tag authelia/authelia authelia:dist
|
docker tag authelia/authelia authelia:dist
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if [[ $BUILDKITE_LABEL =~ ":docker: Build Image" ]] && [[ "${ARCH}" != "coverage" ]]; then
|
||||||
|
echo "--- :react: :swagger: Extract frontend assets"
|
||||||
|
buildkite-agent artifact download "authelia-public_html.tar.gz" .
|
||||||
|
tar xzf authelia-public_html.tar.gz
|
||||||
|
fi
|
||||||
|
|
||||||
if [[ $BUILDKITE_LABEL =~ ":docker: Deploy Image" ]]; then
|
if [[ $BUILDKITE_LABEL =~ ":docker: Deploy Image" ]]; then
|
||||||
buildkite-agent artifact download "authelia-image-${ARCH}*" .
|
buildkite-agent artifact download "authelia-image-${ARCH}*" .
|
||||||
zstdcat authelia-image-"${ARCH}".tar.zst | docker load
|
zstdcat authelia-image-"${ARCH}".tar.zst | docker load
|
||||||
|
|
|
@ -37,6 +37,7 @@ steps:
|
||||||
artifact_paths:
|
artifact_paths:
|
||||||
- "authelia-public_html.tar.gz"
|
- "authelia-public_html.tar.gz"
|
||||||
- "authelia-public_html.tar.gz.sha256"
|
- "authelia-public_html.tar.gz.sha256"
|
||||||
|
key: "unit-test"
|
||||||
if: build.env("CI_BYPASS") != "true"
|
if: build.env("CI_BYPASS") != "true"
|
||||||
|
|
||||||
- wait:
|
- wait:
|
||||||
|
|
|
@ -17,6 +17,8 @@ if [[ "${BUILD_ARCH}" != "coverage" ]]; then
|
||||||
cat << EOF
|
cat << EOF
|
||||||
- "authelia-${BUILD_OS}-${BUILD_ARCH}.tar.gz"
|
- "authelia-${BUILD_OS}-${BUILD_ARCH}.tar.gz"
|
||||||
- "authelia-${BUILD_OS}-${BUILD_ARCH}.tar.gz.sha256"
|
- "authelia-${BUILD_OS}-${BUILD_ARCH}.tar.gz.sha256"
|
||||||
|
depends_on:
|
||||||
|
- "unit-test"
|
||||||
EOF
|
EOF
|
||||||
fi
|
fi
|
||||||
cat << EOF
|
cat << EOF
|
||||||
|
|
13
Dockerfile
13
Dockerfile
|
@ -1,14 +1,3 @@
|
||||||
# ========================================
|
|
||||||
# ===== Build image for the frontend =====
|
|
||||||
# ========================================
|
|
||||||
FROM node:15-alpine AS builder-frontend
|
|
||||||
|
|
||||||
WORKDIR /node/src/app
|
|
||||||
COPY web .
|
|
||||||
|
|
||||||
# Install the dependencies and build
|
|
||||||
RUN yarn install --frozen-lockfile && INLINE_RUNTIME_CHUNK=false yarn build
|
|
||||||
|
|
||||||
# =======================================
|
# =======================================
|
||||||
# ===== Build image for the backend =====
|
# ===== Build image for the backend =====
|
||||||
# =======================================
|
# =======================================
|
||||||
|
@ -23,12 +12,12 @@ RUN apk --no-cache add gcc musl-dev
|
||||||
WORKDIR /go/src/app
|
WORKDIR /go/src/app
|
||||||
|
|
||||||
COPY go.mod go.sum config.template.yml ./
|
COPY go.mod go.sum config.template.yml ./
|
||||||
COPY --from=builder-frontend /node/src/app/build public_html
|
|
||||||
|
|
||||||
RUN go mod download
|
RUN go mod download
|
||||||
|
|
||||||
COPY cmd cmd
|
COPY cmd cmd
|
||||||
COPY internal internal
|
COPY internal internal
|
||||||
|
COPY public_html public_html
|
||||||
|
|
||||||
# Prepare static files to be embedded in Go binary
|
# Prepare static files to be embedded in Go binary
|
||||||
RUN go get -u aletheia.icu/broccoli && \
|
RUN go get -u aletheia.icu/broccoli && \
|
||||||
|
|
|
@ -1,14 +1,3 @@
|
||||||
# ========================================
|
|
||||||
# ===== Build image for the frontend =====
|
|
||||||
# ========================================
|
|
||||||
FROM node:15-alpine AS builder-frontend
|
|
||||||
|
|
||||||
WORKDIR /node/src/app
|
|
||||||
COPY web .
|
|
||||||
|
|
||||||
# Install the dependencies and build
|
|
||||||
RUN yarn install --frozen-lockfile && INLINE_RUNTIME_CHUNK=false yarn build
|
|
||||||
|
|
||||||
# =======================================
|
# =======================================
|
||||||
# ===== Build image for the backend =====
|
# ===== Build image for the backend =====
|
||||||
# =======================================
|
# =======================================
|
||||||
|
@ -26,12 +15,12 @@ RUN apk --no-cache add curl && \
|
||||||
WORKDIR /go/src/app
|
WORKDIR /go/src/app
|
||||||
|
|
||||||
COPY go.mod go.sum config.template.yml ./
|
COPY go.mod go.sum config.template.yml ./
|
||||||
COPY --from=builder-frontend /node/src/app/build public_html
|
|
||||||
|
|
||||||
RUN go mod download
|
RUN go mod download
|
||||||
|
|
||||||
COPY cmd cmd
|
COPY cmd cmd
|
||||||
COPY internal internal
|
COPY internal internal
|
||||||
|
COPY public_html public_html
|
||||||
|
|
||||||
# Prepare static files to be embedded in Go binary
|
# Prepare static files to be embedded in Go binary
|
||||||
RUN go get -u aletheia.icu/broccoli && \
|
RUN go get -u aletheia.icu/broccoli && \
|
||||||
|
|
|
@ -1,14 +1,3 @@
|
||||||
# ========================================
|
|
||||||
# ===== Build image for the frontend =====
|
|
||||||
# ========================================
|
|
||||||
FROM node:15-alpine AS builder-frontend
|
|
||||||
|
|
||||||
WORKDIR /node/src/app
|
|
||||||
COPY web .
|
|
||||||
|
|
||||||
# Install the dependencies and build
|
|
||||||
RUN yarn install --frozen-lockfile && INLINE_RUNTIME_CHUNK=false yarn build
|
|
||||||
|
|
||||||
# =======================================
|
# =======================================
|
||||||
# ===== Build image for the backend =====
|
# ===== Build image for the backend =====
|
||||||
# =======================================
|
# =======================================
|
||||||
|
@ -26,12 +15,12 @@ RUN apk --no-cache add curl && \
|
||||||
WORKDIR /go/src/app
|
WORKDIR /go/src/app
|
||||||
|
|
||||||
COPY go.mod go.sum config.template.yml ./
|
COPY go.mod go.sum config.template.yml ./
|
||||||
COPY --from=builder-frontend /node/src/app/build public_html
|
|
||||||
|
|
||||||
RUN go mod download
|
RUN go mod download
|
||||||
|
|
||||||
COPY cmd cmd
|
COPY cmd cmd
|
||||||
COPY internal internal
|
COPY internal internal
|
||||||
|
COPY public_html public_html
|
||||||
|
|
||||||
# Prepare static files to be embedded in Go binary
|
# Prepare static files to be embedded in Go binary
|
||||||
RUN go get -u aletheia.icu/broccoli && \
|
RUN go get -u aletheia.icu/broccoli && \
|
||||||
|
|
|
@ -7,7 +7,8 @@ WORKDIR /node/src/app
|
||||||
COPY web .
|
COPY web .
|
||||||
|
|
||||||
# Install the dependencies and build
|
# Install the dependencies and build
|
||||||
RUN yarn install --frozen-lockfile && INLINE_RUNTIME_CHUNK=false yarn coverage
|
RUN yarn install --frozen-lockfile && INLINE_RUNTIME_CHUNK=false yarn coverage && \
|
||||||
|
mkdir -p /node/src/app/build/api && cd /node/src/app/build/api/ && touch index.html openapi.yml
|
||||||
|
|
||||||
# =======================================
|
# =======================================
|
||||||
# ===== Build image for the backend =====
|
# ===== Build image for the backend =====
|
||||||
|
|
|
@ -0,0 +1,60 @@
|
||||||
|
<!-- HTML for static distribution bundle build -->
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>Swagger UI</title>
|
||||||
|
<link rel="stylesheet" type="text/css" href="{{.Base}}/api/swagger-ui.css" >
|
||||||
|
<link rel="icon" type="image/png" href="{{.Base}}/api/favicon-32x32.png" sizes="32x32" />
|
||||||
|
<link rel="icon" type="image/png" href="{{.Base}}/api/favicon-16x16.png" sizes="16x16" />
|
||||||
|
<style nonce="{{.CSPNonce}}">
|
||||||
|
html
|
||||||
|
{
|
||||||
|
box-sizing: border-box;
|
||||||
|
overflow: -moz-scrollbars-vertical;
|
||||||
|
overflow-y: scroll;
|
||||||
|
}
|
||||||
|
|
||||||
|
*,
|
||||||
|
*:before,
|
||||||
|
*:after
|
||||||
|
{
|
||||||
|
box-sizing: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
body
|
||||||
|
{
|
||||||
|
margin:0;
|
||||||
|
background: #fafafa;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div id="swagger-ui"></div>
|
||||||
|
|
||||||
|
<script src="{{.Base}}/api/swagger-ui-bundle.js" charset="UTF-8"> </script>
|
||||||
|
<script src="{{.Base}}/api/swagger-ui-standalone-preset.js" charset="UTF-8"> </script>
|
||||||
|
<script nonce="{{.CSPNonce}}">
|
||||||
|
window.onload = function() {
|
||||||
|
// Begin Swagger UI call region
|
||||||
|
const ui = SwaggerUIBundle({
|
||||||
|
url: "{{.Base}}/api/openapi.yml",
|
||||||
|
dom_id: '#swagger-ui',
|
||||||
|
deepLinking: true,
|
||||||
|
presets: [
|
||||||
|
SwaggerUIBundle.presets.apis,
|
||||||
|
SwaggerUIStandalonePreset
|
||||||
|
],
|
||||||
|
plugins: [
|
||||||
|
SwaggerUIBundle.plugins.DownloadUrl
|
||||||
|
],
|
||||||
|
layout: "StandaloneLayout"
|
||||||
|
})
|
||||||
|
// End Swagger UI call region
|
||||||
|
|
||||||
|
window.ui = ui
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,752 @@
|
||||||
|
---
|
||||||
|
openapi: 3.0.0
|
||||||
|
info:
|
||||||
|
title: Authelia API
|
||||||
|
description: Authelia is an open-source authentication and authorization server providing 2-factor authentication and single sign-on (SSO) for your applications via a web portal.
|
||||||
|
contact:
|
||||||
|
name: Authelia Support
|
||||||
|
url: https://github.com/authelia/authelia#contact-options
|
||||||
|
email: team@authelia.com
|
||||||
|
license:
|
||||||
|
name: Apache 2.0
|
||||||
|
url: https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
version: 1.0.0
|
||||||
|
tags:
|
||||||
|
- name: State
|
||||||
|
description: Configuration, health and state endpoints
|
||||||
|
- name: Authentication
|
||||||
|
description: Authentication and verification endpoints
|
||||||
|
- name: Password Reset
|
||||||
|
description: Password reset endpoints
|
||||||
|
- name: User Information
|
||||||
|
description: User configuration endpoints
|
||||||
|
- name: Second Factor
|
||||||
|
description: TOTP, U2F and Duo endpoints
|
||||||
|
paths:
|
||||||
|
/api/configuration:
|
||||||
|
get:
|
||||||
|
tags:
|
||||||
|
- State
|
||||||
|
summary: Application Configuration
|
||||||
|
description: The configuration endpoint provides detailed information including available second factor methods, if any second factor policies exist and the TOTP period configuration.
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: Successful Operation
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/handlers.configuration.ConfigurationBody'
|
||||||
|
"403":
|
||||||
|
description: Forbidden
|
||||||
|
security:
|
||||||
|
- authelia_auth: [ ]
|
||||||
|
/api/health:
|
||||||
|
get:
|
||||||
|
tags:
|
||||||
|
- State
|
||||||
|
summary: Application Health
|
||||||
|
description: The health check endpoint provides information about the health of Authelia.
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: Successful Operation
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/middlewares.OkResponse'
|
||||||
|
/api/state:
|
||||||
|
get:
|
||||||
|
tags:
|
||||||
|
- State
|
||||||
|
summary: User Application State
|
||||||
|
description: The state endpoint provides detailed information including the user, current authenticate level and Authelia's configured default redirection URL.
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: Successful Operation
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/handlers.StateResponse'
|
||||||
|
/api/verify:
|
||||||
|
get:
|
||||||
|
tags:
|
||||||
|
- Authentication
|
||||||
|
summary: Verification
|
||||||
|
description: The verify endpoint provides the ability to verify if a user has the necessary permissions to access a specified domain.
|
||||||
|
parameters:
|
||||||
|
- name: X-Original-URL
|
||||||
|
in: header
|
||||||
|
description: Redirection URL
|
||||||
|
required: true
|
||||||
|
style: simple
|
||||||
|
explode: true
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: Successful Operation
|
||||||
|
headers:
|
||||||
|
remote-user:
|
||||||
|
description: Username
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
example: john
|
||||||
|
remote-name:
|
||||||
|
description: Name
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
example: John Doe
|
||||||
|
remote-email:
|
||||||
|
description: Email
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
example: john.doe@authelia.com
|
||||||
|
remote-groups:
|
||||||
|
description: Comma separated list of Groups
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
example: admin,devs
|
||||||
|
"401":
|
||||||
|
description: Unauthorized
|
||||||
|
security:
|
||||||
|
- authelia_auth: []
|
||||||
|
head:
|
||||||
|
tags:
|
||||||
|
- Authentication
|
||||||
|
summary: Verification
|
||||||
|
description: The verify endpoint provides the ability to verify if a user has the necessary permissions to access a specified domain.
|
||||||
|
parameters:
|
||||||
|
- name: X-Original-URL
|
||||||
|
in: header
|
||||||
|
description: Redirection URL
|
||||||
|
required: true
|
||||||
|
style: simple
|
||||||
|
explode: true
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: Successful Operation
|
||||||
|
headers:
|
||||||
|
remote-user:
|
||||||
|
description: Username
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
example: john
|
||||||
|
remote-name:
|
||||||
|
description: Name
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
example: John Doe
|
||||||
|
remote-email:
|
||||||
|
description: Email
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
example: john.doe@authelia.com
|
||||||
|
remote-groups:
|
||||||
|
description: Comma separated list of Groups
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
example: admin,devs
|
||||||
|
"401":
|
||||||
|
description: Unauthorized
|
||||||
|
security:
|
||||||
|
- authelia_auth: []
|
||||||
|
/api/firstfactor:
|
||||||
|
post:
|
||||||
|
tags:
|
||||||
|
- Authentication
|
||||||
|
summary: Login
|
||||||
|
description: The firstfactor endpoint allows a user to login and generates an authentication cookie for authorization.
|
||||||
|
requestBody:
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/handlers.firstFactorRequestBody'
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: Successful Operation
|
||||||
|
headers:
|
||||||
|
Set-Cookie:
|
||||||
|
style: simple
|
||||||
|
explode: false
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
example: authelia_session=kTTCSLupEUirZVfLeZTijezewFQnNOgs; Path=/
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/handlers.redirectResponse'
|
||||||
|
"401":
|
||||||
|
description: Unauthorized
|
||||||
|
security:
|
||||||
|
- authelia_auth: []
|
||||||
|
/api/logout:
|
||||||
|
post:
|
||||||
|
tags:
|
||||||
|
- Authentication
|
||||||
|
summary: Logout
|
||||||
|
description: The logout endpoint allows a user to logout and destroy a sesssion.
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: Successful Operation
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/middlewares.OkResponse'
|
||||||
|
security:
|
||||||
|
- authelia_auth: [ ]
|
||||||
|
/api/reset-password/identity/start:
|
||||||
|
post:
|
||||||
|
tags:
|
||||||
|
- Password Reset
|
||||||
|
summary: Identity Verification Token Creation
|
||||||
|
description: "This endpoint is step 1 of 3 in the password reset process.\n\nIt validates the user session and sends the user an email with a token and a link to reset their password. This step also generates a session cookie for the rest of the process.\n\nThe same session cookie must be used for all steps in this process."
|
||||||
|
requestBody:
|
||||||
|
required: true
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/handlers.resetPasswordStep1RequestBody'
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: Successful Operation
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/middlewares.OkResponse'
|
||||||
|
security:
|
||||||
|
- authelia_auth: []
|
||||||
|
/api/reset-password/identity/finish:
|
||||||
|
post:
|
||||||
|
tags:
|
||||||
|
- Password Reset
|
||||||
|
summary: Identity Verification Token Validation
|
||||||
|
description: "This endpoint is step 2 of 3 in the password reset process.\n\nIt validates the user session and reset token.\n\nThe same session cookie must be used for all steps in this process."
|
||||||
|
requestBody:
|
||||||
|
required: true
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/middlewares.IdentityVerificationFinishBody'
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: Successful Operation
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/middlewares.OkResponse'
|
||||||
|
security:
|
||||||
|
- authelia_auth: []
|
||||||
|
/api/reset-password:
|
||||||
|
post:
|
||||||
|
tags:
|
||||||
|
- Password Reset
|
||||||
|
summary: Password Reset
|
||||||
|
description: "This endpoint is step 3 of 3 in the password reset process.\n\nIt validates the user session and changes the password.\n\nThe same session cookie must be used for all steps in this process."
|
||||||
|
requestBody:
|
||||||
|
required: true
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/handlers.resetPasswordStep2RequestBody'
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: Successful Operation
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/middlewares.OkResponse'
|
||||||
|
security:
|
||||||
|
- authelia_auth: []
|
||||||
|
/api/user/info:
|
||||||
|
get:
|
||||||
|
tags:
|
||||||
|
- User Information
|
||||||
|
summary: User Configuration
|
||||||
|
description: The user info endpoint provides detailed information including a users display name, preferred and registered second factor method(s).
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: Successful Operation
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/handlers.UserInfo'
|
||||||
|
"403":
|
||||||
|
description: Forbidden
|
||||||
|
security:
|
||||||
|
- authelia_auth: [ ]
|
||||||
|
/api/user/info/2fa_method:
|
||||||
|
post:
|
||||||
|
tags:
|
||||||
|
- User Information
|
||||||
|
summary: User Configuration
|
||||||
|
description: The user info 2fa_method endpoint sets the users preferred second factor method.
|
||||||
|
requestBody:
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/handlers.UserInfo.MethodBody'
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: Successful Operation
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/middlewares.OkResponse'
|
||||||
|
"403":
|
||||||
|
description: Forbidden
|
||||||
|
security:
|
||||||
|
- authelia_auth: [ ]
|
||||||
|
/api/secondfactor/totp/identity/start:
|
||||||
|
post:
|
||||||
|
tags:
|
||||||
|
- Second Factor
|
||||||
|
summary: Identity Verification TOTP Token Creation
|
||||||
|
description: "This endpoint performs identity verification to begin the TOTP device registration process.\n\nThe session generated from this endpoint must be utilised for the subsequent step in the `/api/secondfactor/totp/identity/finish` endpoint."
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: Successful Operation
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/middlewares.OkResponse'
|
||||||
|
security:
|
||||||
|
- authelia_auth: []
|
||||||
|
/api/secondfactor/totp/identity/finish:
|
||||||
|
post:
|
||||||
|
tags:
|
||||||
|
- Second Factor
|
||||||
|
summary: Identity Verification TOTP Token Validation and Device Creation
|
||||||
|
description: "This endpoint performs identity and token verification, upon success also generates TOTP device secret and registers said device.\n\nThe session cookie generated from the `/api/secondfactor/totp/identity/start` endpoint must be utilised for the step here"
|
||||||
|
requestBody:
|
||||||
|
required: true
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/middlewares.IdentityVerificationFinishBody'
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: Successful Operation
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/handlers.TOTPKeyResponse'
|
||||||
|
security:
|
||||||
|
- authelia_auth: []
|
||||||
|
/api/secondfactor/totp:
|
||||||
|
post:
|
||||||
|
tags:
|
||||||
|
- Second Factor
|
||||||
|
summary: Second Factor Authentication - TOTP
|
||||||
|
description: "This endpoint performs second factor authentication with a TOTP key."
|
||||||
|
requestBody:
|
||||||
|
required: true
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/handlers.signTOTPRequestBody'
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: Successful Operation
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/handlers.redirectResponse'
|
||||||
|
"401":
|
||||||
|
description: Unauthorized
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/middlewares.ErrorResponse'
|
||||||
|
security:
|
||||||
|
- authelia_auth: []
|
||||||
|
/api/secondfactor/u2f/sign_request:
|
||||||
|
post:
|
||||||
|
tags:
|
||||||
|
- Second Factor
|
||||||
|
summary: Second Factor Authentication - U2F (Request)
|
||||||
|
description: "This endpoint starts the second factor authentication process with the U2F key."
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: Successful Operation
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/u2f.WebSignRequest'
|
||||||
|
"401":
|
||||||
|
description: Unauthorized
|
||||||
|
security:
|
||||||
|
- authelia_auth: []
|
||||||
|
/api/secondfactor/u2f/sign:
|
||||||
|
post:
|
||||||
|
tags:
|
||||||
|
- Second Factor
|
||||||
|
summary: Second Factor Authentication - U2F
|
||||||
|
description: "This endpoint completes second factor authentication with a U2F key."
|
||||||
|
requestBody:
|
||||||
|
required: true
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: "#/components/schemas/handlers.signU2FRequestBody"
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: Successful Operation
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/handlers.redirectResponse'
|
||||||
|
"401":
|
||||||
|
description: Unauthorized
|
||||||
|
security:
|
||||||
|
- authelia_auth: []
|
||||||
|
/api/secondfactor/u2f/identity/start:
|
||||||
|
post:
|
||||||
|
tags:
|
||||||
|
- Second Factor
|
||||||
|
summary: Identity Verification U2F Token Creation
|
||||||
|
description: "This endpoint performs identity verification to begin the U2F device registration process.\n\nThe session generated from this endpoint must be utilised for the subsequent steps in the `/api/secondfactor/u2f/identity/finish` and `/api/secondfactor/u2f/register` endpoints."
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: Successful Operation
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/middlewares.OkResponse'
|
||||||
|
security:
|
||||||
|
- authelia_auth: []
|
||||||
|
/api/secondfactor/u2f/identity/finish:
|
||||||
|
post:
|
||||||
|
tags:
|
||||||
|
- Second Factor
|
||||||
|
summary: Identity Verification U2F Token Validation
|
||||||
|
description: "This endpoint performs identity and token verification, upon success generates a U2F device registration challenge.\n\nThe session cookie generated from the `/api/secondfactor/u2f/identity/start` endpoint must be utilised for the subsequent steps here and in the `/api/secondfactor/u2f/register` endpoint."
|
||||||
|
requestBody:
|
||||||
|
required: true
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/middlewares.IdentityVerificationFinishBody'
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: Successful Operation
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/u2f.WebRegisterRequest'
|
||||||
|
security:
|
||||||
|
- authelia_auth: []
|
||||||
|
/api/secondfactor/u2f/register:
|
||||||
|
post:
|
||||||
|
tags:
|
||||||
|
- Second Factor
|
||||||
|
summary: U2F Device Registration
|
||||||
|
description: "This endpoint performs U2F device registration."
|
||||||
|
requestBody:
|
||||||
|
required: true
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/u2f.RegisterResponse'
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: Successful Operation
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/middlewares.OkResponse'
|
||||||
|
security:
|
||||||
|
- authelia_auth: []
|
||||||
|
/api/secondfactor/duo:
|
||||||
|
post:
|
||||||
|
tags:
|
||||||
|
- Second Factor
|
||||||
|
summary: Second Factor Authentication - Duo Mobile Push
|
||||||
|
description: "This endpoint performs second factor authentication with a Duo Mobile Push."
|
||||||
|
requestBody:
|
||||||
|
required: true
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/handlers.signDuoRequestBody'
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: Successful Operation
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/handlers.redirectResponse'
|
||||||
|
"401":
|
||||||
|
description: Unauthorized
|
||||||
|
security:
|
||||||
|
- authelia_auth: []
|
||||||
|
components:
|
||||||
|
schemas:
|
||||||
|
handlers.configuration.ConfigurationBody:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
status:
|
||||||
|
type: string
|
||||||
|
example: OK
|
||||||
|
data:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
available_methods:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
example: [totp, u2f, mobile_push]
|
||||||
|
second_factor_enabled:
|
||||||
|
type: boolean
|
||||||
|
description: If second factor is enabled.
|
||||||
|
totp_period:
|
||||||
|
type: integer
|
||||||
|
example: 30
|
||||||
|
handlers.firstFactorRequestBody:
|
||||||
|
required:
|
||||||
|
- username
|
||||||
|
- password
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
username:
|
||||||
|
type: string
|
||||||
|
example: john
|
||||||
|
password:
|
||||||
|
type: string
|
||||||
|
example: password
|
||||||
|
targetURL:
|
||||||
|
type: string
|
||||||
|
example: https://home.example.com
|
||||||
|
keepMeLoggedIn:
|
||||||
|
type: boolean
|
||||||
|
example: true
|
||||||
|
handlers.redirectResponse:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
status:
|
||||||
|
type: string
|
||||||
|
example: OK
|
||||||
|
data:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
redirect:
|
||||||
|
type: string
|
||||||
|
example: https://home.example.com
|
||||||
|
handlers.resetPasswordStep1RequestBody:
|
||||||
|
required:
|
||||||
|
- username
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
username:
|
||||||
|
type: string
|
||||||
|
example: john
|
||||||
|
handlers.resetPasswordStep2RequestBody:
|
||||||
|
required:
|
||||||
|
- password
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
password:
|
||||||
|
type: string
|
||||||
|
example: password
|
||||||
|
handlers.signDuoRequestBody:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
targetURL:
|
||||||
|
type: string
|
||||||
|
example: https://secure.example.com
|
||||||
|
handlers.signTOTPRequestBody:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
token:
|
||||||
|
type: string
|
||||||
|
example: "123456"
|
||||||
|
targetURL:
|
||||||
|
type: string
|
||||||
|
example: https://secure.example.com
|
||||||
|
handlers.signU2FRequestBody:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
targetURL:
|
||||||
|
type: string
|
||||||
|
example: https://secure.example.com
|
||||||
|
signResponse:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
clientData:
|
||||||
|
type: string
|
||||||
|
example: 6prxyWqSsR6MXFchtQRzwZVTedWq7Zdc6XreLt6xRDXKeqJN7vzKAfYcKwRD3AT57bP4YFL4hbxat4LUysBNss
|
||||||
|
keyHandle:
|
||||||
|
type: string
|
||||||
|
example: pWgBrwr9meS5vArdffPtD4Px6AqZS7MfGEf776Rz438ujwHjeXwQEZuK53sRQ4wjeAgRCW4wX9VRj8dyKjc273
|
||||||
|
signatureData:
|
||||||
|
type: string
|
||||||
|
example: p3Pe26B6T2E7EEEc59P4p869qwxy8cQAU2ttyGtGrQHb4XL2ZxCpWrawsSHNSTRZQd7jEW59Y3Ku9vSNRzj7Ly
|
||||||
|
handlers.StateResponse:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
status:
|
||||||
|
type: string
|
||||||
|
example: OK
|
||||||
|
data:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
username:
|
||||||
|
type: string
|
||||||
|
example: john
|
||||||
|
authentication_level:
|
||||||
|
type: integer
|
||||||
|
example: 1
|
||||||
|
default_redirection_url:
|
||||||
|
type: string
|
||||||
|
example: https://home.example.com
|
||||||
|
handlers.TOTPKeyResponse:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
status:
|
||||||
|
type: string
|
||||||
|
example: OK
|
||||||
|
data:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
base32_secret:
|
||||||
|
type: string
|
||||||
|
example: 5ZH7Y5CTFWOXN7EOLGBMMXADRNQFHVUDZSYKCN5HMFAIRSLAWY3Q
|
||||||
|
otpauth_url:
|
||||||
|
type: string
|
||||||
|
example: otpauth://totp/auth.example.com:john?algorithm=SHA1&digits=6&issuer=auth.example.com&period=30&secret=5ZH7Y5CTFWOXN7EOLGBMMXADRNQFHVUDZSYKCN5HMFAIRSLAWY3Q
|
||||||
|
handlers.UserInfo:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
status:
|
||||||
|
type: string
|
||||||
|
example: OK
|
||||||
|
data:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
display_name:
|
||||||
|
type: string
|
||||||
|
example: John Doe
|
||||||
|
method:
|
||||||
|
type: string
|
||||||
|
enum: [totp, u2f, mobile_push]
|
||||||
|
example: totp
|
||||||
|
has_u2f:
|
||||||
|
type: boolean
|
||||||
|
example: false
|
||||||
|
has_totp:
|
||||||
|
type: boolean
|
||||||
|
example: true
|
||||||
|
handlers.UserInfo.MethodBody:
|
||||||
|
required:
|
||||||
|
- method
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
method:
|
||||||
|
type: string
|
||||||
|
enum: [totp, u2f, mobile_push]
|
||||||
|
example: totp
|
||||||
|
middlewares.ErrorResponse:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
status:
|
||||||
|
type: string
|
||||||
|
example: KO
|
||||||
|
message:
|
||||||
|
type: string
|
||||||
|
example: Authentication failed, please retry later.
|
||||||
|
middlewares.IdentityVerificationFinishBody:
|
||||||
|
required:
|
||||||
|
- token
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
token:
|
||||||
|
type: string
|
||||||
|
example: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2MDc5MjU1OTYsImlzcyI6IkF1dGhlbGlhIiwiYWN0aW9uIjoiUmVzZXRQYXNzd29yZCIsInVzZXJuYW1lIjoiQW1pciJ9.636yqRrUCGCe4jsMCsonleX5CYWHncYqZum-YYb6VaY
|
||||||
|
middlewares.OkResponse:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
status:
|
||||||
|
type: string
|
||||||
|
example: OK
|
||||||
|
data:
|
||||||
|
type: object
|
||||||
|
u2f.RegisterResponse:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
version:
|
||||||
|
type: string
|
||||||
|
registrationData:
|
||||||
|
type: string
|
||||||
|
clientData:
|
||||||
|
type: string
|
||||||
|
u2f.WebRegisterRequest:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
status:
|
||||||
|
type: string
|
||||||
|
example: OK
|
||||||
|
data:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
appId:
|
||||||
|
type: string
|
||||||
|
example: https://auth.example.com
|
||||||
|
registerRequests:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
version:
|
||||||
|
type: string
|
||||||
|
example: U2F_V2
|
||||||
|
challenge:
|
||||||
|
type: string
|
||||||
|
example: XGYKUzSmTpM1KxxpekArviW0w0OU2pwwRAocgn8TkVQ
|
||||||
|
registeredKeys:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
appId:
|
||||||
|
type: string
|
||||||
|
example: https://auth.example.com
|
||||||
|
version:
|
||||||
|
type: string
|
||||||
|
example: U2F_V2
|
||||||
|
keyHandle:
|
||||||
|
type: string
|
||||||
|
example: pWgBrwr9meS5vArdffPtD4Px6AqZS7MfGEf776Rz438ujwHjeXwQEZuK53sRQ4wjeAgRCW4wX9VRj8dyKjc273
|
||||||
|
u2f.WebSignRequest:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
status:
|
||||||
|
type: string
|
||||||
|
example: OK
|
||||||
|
data:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
appId:
|
||||||
|
type: string
|
||||||
|
example: https://auth.example.com
|
||||||
|
challenge:
|
||||||
|
type: string
|
||||||
|
example: XGYKUzSmTpM1KxxpekArviW0w0OU2pwwRAocgn8TkVQ
|
||||||
|
registeredKeys:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
appId:
|
||||||
|
type: string
|
||||||
|
example: https://auth.example.com
|
||||||
|
version:
|
||||||
|
type: string
|
||||||
|
example: U2F_V2
|
||||||
|
keyHandle:
|
||||||
|
type: string
|
||||||
|
example: pWgBrwr9meS5vArdffPtD4Px6AqZS7MfGEf776Rz438ujwHjeXwQEZuK53sRQ4wjeAgRCW4wX9VRj8dyKjc273
|
||||||
|
securitySchemes:
|
||||||
|
authelia_auth:
|
||||||
|
type: apiKey
|
||||||
|
name: "{{.Session}}"
|
||||||
|
in: cookie
|
|
@ -17,32 +17,63 @@ func buildAutheliaBinary() {
|
||||||
"GOOS=linux", "GOARCH=amd64", "CGO_ENABLED=1")
|
"GOOS=linux", "GOARCH=amd64", "CGO_ENABLED=1")
|
||||||
|
|
||||||
err := cmd.Run()
|
err := cmd.Run()
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildFrontend() {
|
func buildFrontend() {
|
||||||
// Install npm dependencies.
|
|
||||||
cmd := utils.CommandWithStdout("yarn", "install")
|
cmd := utils.CommandWithStdout("yarn", "install")
|
||||||
cmd.Dir = webDirectory
|
cmd.Dir = webDirectory
|
||||||
|
|
||||||
if err := cmd.Run(); err != nil {
|
err := cmd.Run()
|
||||||
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Then build the frontend.
|
|
||||||
cmd = utils.CommandWithStdout("yarn", "build")
|
cmd = utils.CommandWithStdout("yarn", "build")
|
||||||
cmd.Dir = webDirectory
|
cmd.Dir = webDirectory
|
||||||
|
|
||||||
cmd.Env = append(os.Environ(), "INLINE_RUNTIME_CHUNK=false")
|
cmd.Env = append(os.Environ(), "INLINE_RUNTIME_CHUNK=false")
|
||||||
|
|
||||||
if err := cmd.Run(); err != nil {
|
err = cmd.Run()
|
||||||
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := os.Rename("web/build", "./public_html"); err != nil {
|
err = os.Rename("web/build", "./public_html")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func buildSwagger() {
|
||||||
|
swaggerVer := "3.38.0"
|
||||||
|
cmd := utils.CommandWithStdout("bash", "-c", "wget -q https://github.com/swagger-api/swagger-ui/archive/v"+swaggerVer+".tar.gz -O ./v"+swaggerVer+".tar.gz")
|
||||||
|
|
||||||
|
err := cmd.Run()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd = utils.CommandWithStdout("cp", "-r", "api", "public_html")
|
||||||
|
|
||||||
|
err = cmd.Run()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd = utils.CommandWithStdout("tar", "-C", swaggerDirectory, "--exclude=index.html", "--strip-components=2", "-xf", "v"+swaggerVer+".tar.gz", "swagger-ui-"+swaggerVer+"/dist")
|
||||||
|
|
||||||
|
err = cmd.Run()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd = utils.CommandWithStdout("rm", "./v"+swaggerVer+".tar.gz")
|
||||||
|
|
||||||
|
err = cmd.Run()
|
||||||
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -51,30 +82,28 @@ func generateEmbeddedAssets() {
|
||||||
cmd := utils.CommandWithStdout("go", "get", "-u", "aletheia.icu/broccoli")
|
cmd := utils.CommandWithStdout("go", "get", "-u", "aletheia.icu/broccoli")
|
||||||
|
|
||||||
err := cmd.Run()
|
err := cmd.Run()
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd = utils.CommandWithStdout("go", "generate", ".")
|
cmd = utils.CommandWithStdout("go", "generate", ".")
|
||||||
cmd.Dir = "internal/configuration"
|
cmd.Dir = "internal/configuration"
|
||||||
|
|
||||||
err = cmd.Run()
|
err = cmd.Run()
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd = utils.CommandWithStdout("go", "generate", ".")
|
cmd = utils.CommandWithStdout("go", "generate", ".")
|
||||||
cmd.Dir = "internal/server"
|
cmd.Dir = "internal/server"
|
||||||
|
|
||||||
err = cmd.Run()
|
err = cmd.Run()
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := os.Rename("./public_html", OutputDir+"/public_html"); err != nil {
|
err = os.Rename("./public_html", OutputDir+"/public_html")
|
||||||
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -89,12 +118,15 @@ func Build(cobraCmd *cobra.Command, args []string) {
|
||||||
err := os.MkdirAll(OutputDir, os.ModePerm)
|
err := os.MkdirAll(OutputDir, os.ModePerm)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Debug("Building Authelia frontend...")
|
log.Debug("Building Authelia frontend...")
|
||||||
buildFrontend()
|
buildFrontend()
|
||||||
|
|
||||||
|
log.Debug("Building swagger-ui frontend...")
|
||||||
|
buildSwagger()
|
||||||
|
|
||||||
log.Debug("Building Authelia Go binary...")
|
log.Debug("Building Authelia Go binary...")
|
||||||
generateEmbeddedAssets()
|
generateEmbeddedAssets()
|
||||||
buildAutheliaBinary()
|
buildAutheliaBinary()
|
||||||
|
|
|
@ -12,4 +12,5 @@ var IntermediateDockerImageName = "authelia:dist"
|
||||||
const masterTag = "master"
|
const masterTag = "master"
|
||||||
const stringFalse = "false"
|
const stringFalse = "false"
|
||||||
const stringTrue = "true"
|
const stringTrue = "true"
|
||||||
|
const swaggerDirectory = "public_html/api"
|
||||||
const webDirectory = "web"
|
const webDirectory = "web"
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
package server
|
package server
|
||||||
|
|
||||||
|
const apiFile = "openapi.yml"
|
||||||
|
const indexFile = "index.html"
|
||||||
|
|
||||||
const dev = "dev"
|
const dev = "dev"
|
||||||
|
|
|
@ -1,55 +0,0 @@
|
||||||
package server
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
|
||||||
"text/template"
|
|
||||||
|
|
||||||
"github.com/valyala/fasthttp"
|
|
||||||
|
|
||||||
"github.com/authelia/authelia/internal/logging"
|
|
||||||
"github.com/authelia/authelia/internal/utils"
|
|
||||||
)
|
|
||||||
|
|
||||||
var alphaNumericRunes = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789")
|
|
||||||
|
|
||||||
// ServeIndex serve the index.html file with nonce generated for supporting
|
|
||||||
// restrictive CSP while using material-ui from the embedded virtual filesystem.
|
|
||||||
//go:generate broccoli -src ../../public_html -o public_html
|
|
||||||
func ServeIndex(publicDir, base, rememberMe, resetPassword string) fasthttp.RequestHandler {
|
|
||||||
f, err := br.Open(publicDir + "/index.html")
|
|
||||||
if err != nil {
|
|
||||||
logging.Logger().Fatalf("Unable to open index.html: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
b, err := ioutil.ReadAll(f)
|
|
||||||
if err != nil {
|
|
||||||
logging.Logger().Fatalf("Unable to read index.html: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
tmpl, err := template.New("index").Parse(string(b))
|
|
||||||
if err != nil {
|
|
||||||
logging.Logger().Fatalf("Unable to parse index.html template: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return func(ctx *fasthttp.RequestCtx) {
|
|
||||||
nonce := utils.RandomString(32, alphaNumericRunes)
|
|
||||||
|
|
||||||
ctx.SetContentType("text/html; charset=utf-8")
|
|
||||||
|
|
||||||
if os.Getenv("ENVIRONMENT") == dev {
|
|
||||||
ctx.Response.Header.Add("Content-Security-Policy", fmt.Sprintf("default-src 'self' 'unsafe-eval'; object-src 'none'; style-src 'self' 'nonce-%s'", nonce))
|
|
||||||
} else {
|
|
||||||
ctx.Response.Header.Add("Content-Security-Policy", fmt.Sprintf("default-src 'self'; object-src 'none'; style-src 'self' 'nonce-%s'", nonce))
|
|
||||||
}
|
|
||||||
|
|
||||||
err := tmpl.Execute(ctx.Response.BodyWriter(), struct{ Base, CSPNonce, RememberMe, ResetPassword string }{Base: base, CSPNonce: nonce, RememberMe: rememberMe, ResetPassword: resetPassword})
|
|
||||||
if err != nil {
|
|
||||||
ctx.Error("An error occurred", 503)
|
|
||||||
logging.Logger().Errorf("Unable to execute template: %v", err)
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -4,4 +4,4 @@ import "aletheia.icu/broccoli/fs"
|
||||||
|
|
||||||
// Mock the embedded filesystem for unit tests. The bundle is built from an empty file and
|
// Mock the embedded filesystem for unit tests. The bundle is built from an empty file and
|
||||||
// allows to run the dev workflow without failure.
|
// allows to run the dev workflow without failure.
|
||||||
var br = fs.New(false, []byte("\x1b~\x00\x80\x8d\x94n\xc2|\x84J\xf7\xbfn\xfd\xf7w;.\x8d m\xb2&\xd1Z\xec\xb2\x05\xb9\xc00\x8a\xf7(\x80^78\t(\f\f\xc3p\xc2\xc1\x06[a\xa2\xb3\xa4P\xe5\xa14\xfb\x19\xb2cp\xf6\x90-Z\xb2\x11\xe0l\xa1\x80\\\x95Vh\t\xc5\x06\x16\xfa\x8c\xc0\"!\xa5\xcf\xf7$\x9a\xb2\a`\xc6\x18\xc8~\xce8\r\x16Z\x9d\xc3\xe3\xff\x00"))
|
var br = fs.New(false, []byte("\x1b\xf7\x00\x00ħ?\xf5\xbd\xaci\x936'\x9e\x8b\xe5*\xda\xfbֵ@6\x96\xa0\"e\xc9xz\x92eaH)\aA\x18a`m\xcd#\xfd\xc1\xbe\x1d\xe4h\x87:\xd9h/2~\x17\x92'w~J\x94\xe6\x178?\x80n\xbe˔\xea@\x95J/n\x82V\xfa\x02\x1etB\x81\xa0t\xa2·\xf5\xfe\x02̿\xf9\x05E\xb2Q\xcb\xe5\xea\xb6\xdfQ\xdfS\n\x0e\xff蓼\xe4\xefR-Nkʍ\x1d\xed\xd5 [&*\x0f\f\x83\xd6\xec\x92\v\x1b\x19\xb4\x1d\x91\x00"))
|
||||||
|
|
|
@ -25,22 +25,28 @@ import (
|
||||||
// StartServer start Authelia server with the given configuration and providers.
|
// StartServer start Authelia server with the given configuration and providers.
|
||||||
func StartServer(configuration schema.Configuration, providers middlewares.Providers) {
|
func StartServer(configuration schema.Configuration, providers middlewares.Providers) {
|
||||||
autheliaMiddleware := middlewares.AutheliaMiddleware(configuration, providers)
|
autheliaMiddleware := middlewares.AutheliaMiddleware(configuration, providers)
|
||||||
embeddedAssets := "/public_html"
|
embeddedAssets := "/public_html/"
|
||||||
|
swaggerAssets := embeddedAssets + "api/"
|
||||||
rememberMe := strconv.FormatBool(configuration.Session.RememberMeDuration != "0")
|
rememberMe := strconv.FormatBool(configuration.Session.RememberMeDuration != "0")
|
||||||
resetPassword := strconv.FormatBool(!configuration.AuthenticationBackend.DisableResetPassword)
|
resetPassword := strconv.FormatBool(!configuration.AuthenticationBackend.DisableResetPassword)
|
||||||
|
|
||||||
rootFiles := []string{"favicon.ico", "manifest.json", "robots.txt"}
|
rootFiles := []string{"favicon.ico", "manifest.json", "robots.txt"}
|
||||||
|
|
||||||
serveIndexHandler := ServeIndex(embeddedAssets, configuration.Server.Path, rememberMe, resetPassword)
|
serveIndexHandler := ServeTemplatedFile(embeddedAssets, indexFile, configuration.Server.Path, configuration.Session.Name, rememberMe, resetPassword)
|
||||||
|
serveSwaggerHandler := ServeTemplatedFile(swaggerAssets, indexFile, configuration.Server.Path, configuration.Session.Name, rememberMe, resetPassword)
|
||||||
|
serveSwaggerAPIHandler := ServeTemplatedFile(swaggerAssets, apiFile, configuration.Server.Path, configuration.Session.Name, rememberMe, resetPassword)
|
||||||
|
|
||||||
r := router.New()
|
r := router.New()
|
||||||
r.GET("/", serveIndexHandler)
|
r.GET("/", serveIndexHandler)
|
||||||
|
r.GET("/api/", serveSwaggerHandler)
|
||||||
|
r.GET("/api/"+apiFile, serveSwaggerAPIHandler)
|
||||||
|
|
||||||
for _, f := range rootFiles {
|
for _, f := range rootFiles {
|
||||||
r.GET("/"+f, fasthttpadaptor.NewFastHTTPHandler(br.Serve(embeddedAssets)))
|
r.GET("/"+f, fasthttpadaptor.NewFastHTTPHandler(br.Serve(embeddedAssets)))
|
||||||
}
|
}
|
||||||
|
|
||||||
r.GET("/static/{filepath:*}", fasthttpadaptor.NewFastHTTPHandler(br.Serve(embeddedAssets)))
|
r.GET("/static/{filepath:*}", fasthttpadaptor.NewFastHTTPHandler(br.Serve(embeddedAssets)))
|
||||||
|
r.GET("/api/{filepath:*}", fasthttpadaptor.NewFastHTTPHandler(br.Serve(embeddedAssets)))
|
||||||
|
|
||||||
r.GET("/api/health", autheliaMiddleware(handlers.HealthGet))
|
r.GET("/api/health", autheliaMiddleware(handlers.HealthGet))
|
||||||
r.GET("/api/state", autheliaMiddleware(handlers.StateGet))
|
r.GET("/api/state", autheliaMiddleware(handlers.StateGet))
|
||||||
|
|
|
@ -0,0 +1,65 @@
|
||||||
|
package server
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"text/template"
|
||||||
|
|
||||||
|
"github.com/valyala/fasthttp"
|
||||||
|
|
||||||
|
"github.com/authelia/authelia/internal/logging"
|
||||||
|
"github.com/authelia/authelia/internal/utils"
|
||||||
|
)
|
||||||
|
|
||||||
|
var alphaNumericRunes = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789")
|
||||||
|
|
||||||
|
// ServeTemplatedFile serves a templated version of a specified file,
|
||||||
|
// this is utilised to pass information between the backend and frontend
|
||||||
|
// and generate a nonce to support a restrictive CSP while using material-ui.
|
||||||
|
//go:generate broccoli -src ../../public_html -o public_html
|
||||||
|
func ServeTemplatedFile(publicDir, file, base, session, rememberMe, resetPassword string) fasthttp.RequestHandler {
|
||||||
|
f, err := br.Open(publicDir + file)
|
||||||
|
if err != nil {
|
||||||
|
logging.Logger().Fatalf("Unable to open %s: %s", file, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
b, err := ioutil.ReadAll(f)
|
||||||
|
if err != nil {
|
||||||
|
logging.Logger().Fatalf("Unable to read %s: %s", file, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
tmpl, err := template.New("file").Parse(string(b))
|
||||||
|
if err != nil {
|
||||||
|
logging.Logger().Fatalf("Unable to parse %s template: %s", file, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return func(ctx *fasthttp.RequestCtx) {
|
||||||
|
nonce := utils.RandomString(32, alphaNumericRunes)
|
||||||
|
|
||||||
|
switch extension := filepath.Ext(file); extension {
|
||||||
|
case ".html":
|
||||||
|
ctx.SetContentType("text/html; charset=utf-8")
|
||||||
|
default:
|
||||||
|
ctx.SetContentType("text/plain; charset=utf-8")
|
||||||
|
}
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case os.Getenv("ENVIRONMENT") == dev:
|
||||||
|
ctx.Response.Header.Add("Content-Security-Policy", fmt.Sprintf("default-src 'self' 'unsafe-eval'; object-src 'none'; style-src 'self' 'nonce-%s'", nonce))
|
||||||
|
case publicDir == "/public_html/api/":
|
||||||
|
ctx.Response.Header.Add("Content-Security-Policy", fmt.Sprintf("base-uri 'self' ; default-src 'self' ; img-src 'self' https://validator.swagger.io data: ; object-src 'none' ; script-src 'self' 'unsafe-inline' 'nonce-%s' ; style-src 'self' 'nonce-%s'", nonce, nonce))
|
||||||
|
default:
|
||||||
|
ctx.Response.Header.Add("Content-Security-Policy", fmt.Sprintf("default-src 'self' ; object-src 'none'; style-src 'self' 'nonce-%s'", nonce))
|
||||||
|
}
|
||||||
|
|
||||||
|
err := tmpl.Execute(ctx.Response.BodyWriter(), struct{ Base, CSPNonce, Session, RememberMe, ResetPassword string }{Base: base, CSPNonce: nonce, Session: session, RememberMe: rememberMe, ResetPassword: resetPassword})
|
||||||
|
if err != nil {
|
||||||
|
ctx.Error("An error occurred", 503)
|
||||||
|
logging.Logger().Errorf("Unable to execute template: %v", err)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -17,6 +17,7 @@
|
||||||
.env.development.local
|
.env.development.local
|
||||||
.env.test.local
|
.env.test.local
|
||||||
.env.production.local
|
.env.production.local
|
||||||
|
.eslintcache
|
||||||
|
|
||||||
npm-debug.log*
|
npm-debug.log*
|
||||||
yarn-debug.log*
|
yarn-debug.log*
|
||||||
|
|
Loading…
Reference in New Issue