blasphem/pkg/auth/authenticator.go

119 lines
2.3 KiB
Go
Raw Normal View History

2022-09-30 23:54:21 -04:00
package auth
import (
2022-10-25 00:16:29 -04:00
"errors"
2022-09-30 23:54:21 -04:00
"io"
"net/http"
"github.com/labstack/echo/v4"
"dynatron.me/x/blasphem/pkg/frontend"
2022-10-25 00:16:29 -04:00
"dynatron.me/x/blasphem/pkg/storage"
)
var (
ErrInvalidAuth = errors.New("invalid auth")
ErrInvalidHandler = errors.New("no such handler")
2022-09-30 23:54:21 -04:00
)
type Authenticator struct {
2022-10-25 00:16:29 -04:00
Flows FlowStore
Providers map[string]AuthProvider
2022-09-30 23:54:21 -04:00
}
2022-10-25 00:16:29 -04:00
func (a *Authenticator) Provider(name string) AuthProvider {
p, ok := a.Providers[name]
if !ok {
return nil
}
return p
}
func (a *Authenticator) InitAuth(s storage.Store) error {
2022-09-30 23:54:21 -04:00
a.Flows = make(FlowStore)
2022-10-25 00:16:29 -04:00
hap, err := NewHAProvider(s)
if err != nil {
return err
}
// XXX: yuck
a.Providers = map[string]AuthProvider{
hap.ProviderType(): hap,
}
return nil
2022-09-30 23:54:21 -04:00
}
type AuthProvider interface {
ProviderName() string
ProviderID() *string
ProviderType() string
2022-10-25 00:16:29 -04:00
ProviderBase() AuthProviderBase
FlowSchema() []FlowSchemaItem
ValidateCreds(reqMap map[string]interface{}) bool
2022-09-30 23:54:21 -04:00
}
type AuthProviderBase struct {
Name string `json:"name"`
ID *string `json:"id"`
Type string `json:"type"`
}
2022-10-25 00:16:29 -04:00
func (bp *AuthProviderBase) ProviderName() string { return bp.Name }
func (bp *AuthProviderBase) ProviderID() *string { return bp.ID }
func (bp *AuthProviderBase) ProviderType() string { return bp.Type }
func (bp *AuthProviderBase) ProviderBase() AuthProviderBase { return *bp }
2022-09-30 23:54:21 -04:00
var HomeAssistant = "homeassistant"
// TODO: make this configurable
2022-10-25 00:16:29 -04:00
func (a *Authenticator) ProvidersHandler(c echo.Context) error {
providers := []AuthProviderBase{
a.Provider(HomeAssistant).ProviderBase(),
2022-09-30 23:54:21 -04:00
}
return c.JSON(http.StatusOK, providers)
}
func (s *Authenticator) AuthorizeHandler(c echo.Context) error {
authContents, err := frontend.RootFS.Open("authorize.html")
if err != nil {
return err
}
defer authContents.Close()
b, err := io.ReadAll(authContents)
if err != nil {
return err
}
return c.HTML(http.StatusOK, string(b))
}
2022-10-25 00:16:29 -04:00
func (a *Authenticator) Check(f *Flow, rm map[string]interface{}) error {
cID, hasCID := rm["client_id"]
if !hasCID || cID != f.request.ClientID {
return ErrInvalidAuth
}
for _, h := range f.Handler {
if h == nil {
return ErrInvalidHandler
}
p := a.Provider(*h)
if p == nil {
return ErrInvalidAuth
}
success := p.ValidateCreds(rm)
if success {
return nil
}
}
return ErrInvalidAuth
}