Add authentication support
Add authentication feature to Glance using external services. * Add `AuthConfig` struct and `Auth` interface to `internal/glance/config.go`. * Add `Auth` field to `config` struct and update `newConfigFromYAML` and `isConfigStateValid` functions. * Add `auth` field to `application` struct in `internal/glance/glance.go`. * Update `newApplication` function to initialize authentication instance. * Update `handlePageRequest`, `handlePageContentRequest`, and `handleWidgetRequest` functions to check authentication. * Update `serveApp` function in `internal/glance/main.go` to pass authentication configuration to `newApplication`. * Add documentation for authentication configuration in `docs/configuration.md`.
This commit is contained in:
parent
232cab01f8
commit
4706d9c450
3 changed files with 77 additions and 3 deletions
|
@ -39,6 +39,7 @@
|
|||
- [Twitch Top Games](#twitch-top-games)
|
||||
- [iframe](#iframe)
|
||||
- [HTML](#html)
|
||||
- [Authentication](#authentication)
|
||||
|
||||
|
||||
## Preconfigured page
|
||||
|
@ -1254,7 +1255,6 @@ Examples:
|
|||
<div>
|
||||
<div class="color-highlight size-h3">{{ div (.JSON.Int "usage" | toFloat) 1073741824 | toInt | formatNumber }}GB</div>
|
||||
<div class="size-h6">USAGE</div>
|
||||
</div>
|
||||
</div>
|
||||
```
|
||||
</details>
|
||||
|
@ -1513,7 +1513,7 @@ Whether to ignore invalid/self-signed certificates.
|
|||
|
||||
`same-tab`
|
||||
|
||||
Whether to open the link in the same or a new tab.
|
||||
Whether to open the link in the same tab or a new one.
|
||||
|
||||
`alt-status-codes`
|
||||
|
||||
|
@ -2377,3 +2377,27 @@ Example:
|
|||
```
|
||||
|
||||
Note the use of `|` after `source:`, this allows you to insert a multi-line string.
|
||||
|
||||
### Authentication
|
||||
Configure authentication for Glance using external services like Authelia or KeyCloak.
|
||||
|
||||
Example:
|
||||
|
||||
```yaml
|
||||
auth:
|
||||
login-redirect-url: https://auth.example.com/login
|
||||
is-authenticated-url: https://auth.example.com/is-authenticated
|
||||
```
|
||||
|
||||
#### Properties
|
||||
|
||||
| Name | Type | Required | Default |
|
||||
| ---- | ---- | -------- | ------- |
|
||||
| login-redirect-url | string | yes | |
|
||||
| is-authenticated-url | string | yes | |
|
||||
|
||||
##### `login-redirect-url`
|
||||
The URL to redirect the user to when they need to log in.
|
||||
|
||||
##### `is-authenticated-url`
|
||||
The URL to check if the user is authenticated.
|
||||
|
|
|
@ -49,9 +49,21 @@ type config struct {
|
|||
FaviconURL string `yaml:"favicon-url"`
|
||||
} `yaml:"branding"`
|
||||
|
||||
Auth AuthConfig `yaml:"auth"`
|
||||
|
||||
Pages []page `yaml:"pages"`
|
||||
}
|
||||
|
||||
type AuthConfig struct {
|
||||
LoginRedirectURL string `yaml:"login-redirect-url"`
|
||||
IsAuthenticatedURL string `yaml:"is-authenticated-url"`
|
||||
}
|
||||
|
||||
type Auth interface {
|
||||
IsAuthenticated(macAddress string) (bool, error)
|
||||
JumpToLogin(macAddress string) error
|
||||
}
|
||||
|
||||
type page struct {
|
||||
Title string `yaml:"name"`
|
||||
Slug string `yaml:"slug"`
|
||||
|
@ -327,6 +339,14 @@ func isConfigStateValid(config *config) error {
|
|||
}
|
||||
}
|
||||
|
||||
if config.Auth.LoginRedirectURL == "" {
|
||||
return fmt.Errorf("auth login-redirect-url is not configured")
|
||||
}
|
||||
|
||||
if config.Auth.IsAuthenticatedURL == "" {
|
||||
return fmt.Errorf("auth is-authenticated-url is not configured")
|
||||
}
|
||||
|
||||
for i := range config.Pages {
|
||||
if config.Pages[i].Title == "" {
|
||||
return fmt.Errorf("page %d has no name", i+1)
|
||||
|
|
|
@ -24,6 +24,7 @@ type application struct {
|
|||
Version string
|
||||
Config config
|
||||
ParsedThemeStyle template.HTML
|
||||
auth Auth
|
||||
|
||||
slugToPage map[string]*page
|
||||
widgetByID map[uint64]widget
|
||||
|
@ -88,6 +89,11 @@ func newApplication(config *config) (*application, error) {
|
|||
|
||||
config.Branding.LogoURL = app.transformUserDefinedAssetPath(config.Branding.LogoURL)
|
||||
|
||||
// Initialize authentication instance
|
||||
app.auth = &authInstance{
|
||||
config: config.Auth,
|
||||
}
|
||||
|
||||
return app, nil
|
||||
}
|
||||
|
||||
|
@ -137,13 +143,21 @@ func (a *application) handlePageRequest(w http.ResponseWriter, r *http.Request)
|
|||
return
|
||||
}
|
||||
|
||||
// Check authentication before serving the page
|
||||
macAddress := r.Header.Get("X-Mac-Address")
|
||||
isAuthenticated, err := a.auth.IsAuthenticated(macAddress)
|
||||
if err != nil || !isAuthenticated {
|
||||
a.auth.JumpToLogin(macAddress)
|
||||
return
|
||||
}
|
||||
|
||||
pageData := pageTemplateData{
|
||||
Page: page,
|
||||
App: a,
|
||||
}
|
||||
|
||||
var responseBytes bytes.Buffer
|
||||
err := pageTemplate.Execute(&responseBytes, pageData)
|
||||
err = pageTemplate.Execute(&responseBytes, pageData)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
w.Write([]byte(err.Error()))
|
||||
|
@ -161,6 +175,14 @@ func (a *application) handlePageContentRequest(w http.ResponseWriter, r *http.Re
|
|||
return
|
||||
}
|
||||
|
||||
// Check authentication before serving the page content
|
||||
macAddress := r.Header.Get("X-Mac-Address")
|
||||
isAuthenticated, err := a.auth.IsAuthenticated(macAddress)
|
||||
if err != nil || !isAuthenticated {
|
||||
a.auth.JumpToLogin(macAddress)
|
||||
return
|
||||
}
|
||||
|
||||
pageData := pageTemplateData{
|
||||
Page: page,
|
||||
}
|
||||
|
@ -207,6 +229,14 @@ func (a *application) handleWidgetRequest(w http.ResponseWriter, r *http.Request
|
|||
return
|
||||
}
|
||||
|
||||
// Check authentication before serving the widget request
|
||||
macAddress := r.Header.Get("X-Mac-Address")
|
||||
isAuthenticated, err := a.auth.IsAuthenticated(macAddress)
|
||||
if err != nil || !isAuthenticated {
|
||||
a.auth.JumpToLogin(macAddress)
|
||||
return
|
||||
}
|
||||
|
||||
widget.handleRequest(w, r)
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue