Skip to content

Commit

Permalink
Update docs (#512)
Browse files Browse the repository at this point in the history
* fix doc

* fix basic auth middleware

* update docs
  • Loading branch information
yohamta authored Jan 1, 2024
1 parent 22f3138 commit cc0c36e
Show file tree
Hide file tree
Showing 8 changed files with 107 additions and 4 deletions.
51 changes: 51 additions & 0 deletions docs/source/api_token.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
.. _API Token:

API Token
=====================

.. contents::
:local:

To enable API token for Dagu, follow these steps:

#. Set the environment variables to configure basic authentication:

.. code-block:: bash
export DAGU_IS_AUTHTOKEN=1
export DAGU_AUTHTOKEN="<arbitrary token string>"
Replace ``<arbitrary token string>`` with a random string of your choice. This string will be used as the API token for Dagu.

#. Alternatively, create an ``admin.yaml`` file in the ``$DAGU_HOME`` directory (default: ``$HOME/.dagu/``) to override the default configuration values.

.. code-block:: yaml
# API Token
isAuthToken: true
authToken: "<arbitrary token string>"
#. You can enable HTTPS by configuring the following environment variables:

.. code-block:: bash
export DAGU_CERT_FILE="<path-to-cert-file>"
export DAGU_KEY_FILE="<path-to-key-file>"
Replace ``<path-to-cert-file>`` and ``<path-to-key-file>`` with the paths to your certificate and key files.

See :ref:`Configuration Options` for more information on the configuration file.

#. Enable Basic Authentication as well if you want to use the Web UI along with the API token. **Without basic authentication config, you will not be able to access the Web UI.**

.. code-block:: bash
export DAGU_IS_BASICAUTH=1
export DAGU_USERNAME="<username>"
export DAGU_PASSWORD="<password>"
Replace ``<username>`` and ``<password>`` with your username and password.

See :ref:`Basic Auth` for more information on the basic authentication.

See :ref:`REST API` for more information on the REST API.
2 changes: 1 addition & 1 deletion docs/source/auth.rst
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ To enable basic authentication for Dagu, follow these steps:
Replace ``<your-username>`` and ``<your-password>`` with your desired username and password.

#. Alternatively, create an ``config.yaml`` file in the ``$DAGU_HOME`` directory (default: ``$HOME/.dagu/``) to override the default configuration values. Add the following lines under the ``# Basic Auth`` section:
#. Alternatively, create an ``admin.yaml`` file in the ``$DAGU_HOME`` directory (default: ``$HOME/.dagu/``) to override the default configuration values.

.. code-block:: yaml
Expand Down
4 changes: 4 additions & 0 deletions docs/source/config.rst
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,10 @@ You can create ``admin.yaml`` file in the ``$DAGU_HOME`` directory (default: ``$
basicAuthUsername: <username for basic auth of web UI> # basic auth user
basicAuthPassword: <password for basic auth of web UI> # basic auth password
# API Token
isAuthToken: <true|false> # enables API token
authToken: <token for API access> # API token
# Base Config
baseConfig: <base DAG config path> # default: ${DAGU_HOME}/config.yaml
Expand Down
1 change: 1 addition & 0 deletions docs/source/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ Contents
examples
config
auth
api_token
executors
email
scheduler
Expand Down
2 changes: 2 additions & 0 deletions docs/source/rest.rst
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
.. _REST API:

REST API Docs
=============

Expand Down
23 changes: 20 additions & 3 deletions service/frontend/middleware/basic_auth.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
package middleware

import (
"crypto/subtle"
"fmt"
"net/http"
"strings"

"github.com/go-chi/chi/v5/middleware"
)

func BasicAuth(realm string, creds map[string]string) func(next http.Handler) http.Handler {
Expand All @@ -15,7 +15,19 @@ func BasicAuth(realm string, creds map[string]string) func(next http.Handler) ht
next.ServeHTTP(w, r)
return
}
middleware.BasicAuth("restricted", creds)(next).ServeHTTP(w, r)
user, pass, ok := r.BasicAuth()
if !ok {
basicAuthFailed(w, realm)
return
}

credPass, credUserOk := creds[user]
if !credUserOk || subtle.ConstantTimeCompare([]byte(pass), []byte(credPass)) != 1 {
basicAuthFailed(w, realm)
return
}

next.ServeHTTP(w, r.WithContext(withAuthenticated(r.Context())))
})
}
}
Expand All @@ -26,3 +38,8 @@ func skipBasicAuth(authHeader []string) bool {
len(authHeader) >= 2 &&
authHeader[0] == "Bearer"
}

func basicAuthFailed(w http.ResponseWriter, realm string) {
w.Header().Add("WWW-Authenticate", fmt.Sprintf(`Basic realm="%s"`, realm))
w.WriteHeader(http.StatusUnauthorized)
}
19 changes: 19 additions & 0 deletions service/frontend/middleware/global.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package middleware

import (
"context"
"net/http"
"strings"

Expand Down Expand Up @@ -28,6 +29,24 @@ func SetupGlobalMiddleware(handler http.Handler) http.Handler {
return next
}

type authCtxKey struct{}

type authCtx struct {
authenticated bool
}

func withAuthenticated(ctx context.Context) context.Context {
return context.WithValue(ctx, authCtxKey{}, &authCtx{authenticated: true})
}

func isAuthenticated(ctx context.Context) bool {
if ctx == nil {
return false
}
auth, ok := ctx.Value(authCtxKey{}).(*authCtx)
return ok && auth.authenticated
}

var (
defaultHandler http.Handler
authBasic *AuthBasic
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@ import (
func TokenAuth(realm string, token string) func(next http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if skipTokenAuth(*r) {
next.ServeHTTP(w, r)
return
}

authHeader := strings.Split(r.Header.Get("Authorization"), " ")
if len(authHeader) < 2 {
tokenAuthFailed(w, realm)
Expand All @@ -34,6 +39,10 @@ func TokenAuth(realm string, token string) func(next http.Handler) http.Handler
}
}

func skipTokenAuth(r http.Request) bool {
return isAuthenticated(r.Context())
}

func tokenAuthFailed(w http.ResponseWriter, realm string) {
w.Header().Add("WWW-Authenticate", fmt.Sprintf(`Bearer realm="%s"`, realm))
w.WriteHeader(http.StatusUnauthorized)
Expand Down

0 comments on commit cc0c36e

Please sign in to comment.