feat: initial commit
This commit is contained in:
138
internal/setup/auth_handler.go
Normal file
138
internal/setup/auth_handler.go
Normal file
@ -0,0 +1,138 @@
|
||||
package setup
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/rand"
|
||||
"fmt"
|
||||
|
||||
"forge.cadoles.com/wpetit/clearcase/internal/config"
|
||||
"forge.cadoles.com/wpetit/clearcase/internal/http/handler/webui/auth"
|
||||
"github.com/gorilla/sessions"
|
||||
"github.com/markbates/goth"
|
||||
"github.com/markbates/goth/gothic"
|
||||
"github.com/markbates/goth/providers/github"
|
||||
"github.com/markbates/goth/providers/google"
|
||||
"github.com/markbates/goth/providers/openidConnect"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
func NewAuthHandlerFromConfig(ctx context.Context, conf *config.Config) (*auth.Handler, error) {
|
||||
// Configure sessions store
|
||||
|
||||
keyPairs := make([][]byte, 0)
|
||||
if len(conf.HTTP.Session.Keys) == 0 {
|
||||
key, err := getRandomBytes(32)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not generate cookie signing key")
|
||||
}
|
||||
|
||||
keyPairs = append(keyPairs, key)
|
||||
} else {
|
||||
for _, k := range conf.HTTP.Session.Keys {
|
||||
keyPairs = append(keyPairs, []byte(k))
|
||||
}
|
||||
}
|
||||
|
||||
sessionStore := sessions.NewCookieStore(keyPairs...)
|
||||
|
||||
sessionStore.MaxAge(int(conf.HTTP.Session.Cookie.MaxAge))
|
||||
sessionStore.Options.Path = conf.HTTP.Session.Cookie.Path
|
||||
sessionStore.Options.HttpOnly = conf.HTTP.Session.Cookie.HTTPOnly
|
||||
sessionStore.Options.Secure = conf.HTTP.Session.Cookie.Secure
|
||||
|
||||
// Configure providers
|
||||
|
||||
gothProviders := make([]goth.Provider, 0)
|
||||
providers := make([]auth.Provider, 0)
|
||||
|
||||
if conf.Auth.Providers.Google.Key != "" && conf.Auth.Providers.Google.Secret != "" {
|
||||
googleProvider := google.New(
|
||||
conf.Auth.Providers.Google.Key,
|
||||
conf.Auth.Providers.Google.Secret,
|
||||
fmt.Sprintf("%s/auth/providers/google/callback", conf.HTTP.BaseURL),
|
||||
conf.Auth.Providers.Google.Scopes...,
|
||||
)
|
||||
|
||||
gothProviders = append(gothProviders, googleProvider)
|
||||
|
||||
providers = append(providers, auth.Provider{
|
||||
ID: googleProvider.Name(),
|
||||
Label: "Google",
|
||||
Icon: "fa-google",
|
||||
})
|
||||
}
|
||||
|
||||
if conf.Auth.Providers.Github.Key != "" && conf.Auth.Providers.Github.Secret != "" {
|
||||
githubProvider := github.New(
|
||||
conf.Auth.Providers.Github.Key,
|
||||
conf.Auth.Providers.Github.Secret,
|
||||
fmt.Sprintf("%s/auth/providers/github/callback", conf.HTTP.BaseURL),
|
||||
conf.Auth.Providers.Github.Scopes...,
|
||||
)
|
||||
|
||||
gothProviders = append(gothProviders, githubProvider)
|
||||
|
||||
providers = append(providers, auth.Provider{
|
||||
ID: githubProvider.Name(),
|
||||
Label: "Github",
|
||||
Icon: "fa-github",
|
||||
})
|
||||
}
|
||||
|
||||
if conf.Auth.Providers.OIDC.Key != "" && conf.Auth.Providers.OIDC.Secret != "" {
|
||||
oidcProvider, err := openidConnect.New(
|
||||
conf.Auth.Providers.OIDC.Key,
|
||||
conf.Auth.Providers.OIDC.Secret,
|
||||
fmt.Sprintf("%s/auth/providers/openid-connect/callback", conf.HTTP.BaseURL),
|
||||
conf.Auth.Providers.OIDC.DiscoveryURL,
|
||||
conf.Auth.Providers.OIDC.Scopes...,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not configure oidc provider")
|
||||
}
|
||||
|
||||
gothProviders = append(gothProviders, oidcProvider)
|
||||
|
||||
providers = append(providers, auth.Provider{
|
||||
ID: oidcProvider.Name(),
|
||||
Label: conf.Auth.Providers.OIDC.Label,
|
||||
Icon: conf.Auth.Providers.OIDC.Icon,
|
||||
})
|
||||
}
|
||||
|
||||
goth.UseProviders(gothProviders...)
|
||||
gothic.Store = sessionStore
|
||||
|
||||
opts := []auth.OptionFunc{
|
||||
auth.WithProviders(providers...),
|
||||
}
|
||||
|
||||
if conf.Auth.DefaultAdmin.Email != "" && conf.Auth.DefaultAdmin.Provider != "" {
|
||||
opts = append(opts, auth.WithDefaultAdmin(auth.DefaultAdmin{
|
||||
Provider: conf.Auth.DefaultAdmin.Provider,
|
||||
Email: conf.Auth.DefaultAdmin.Email,
|
||||
}))
|
||||
}
|
||||
|
||||
auth := auth.NewHandler(
|
||||
sessionStore,
|
||||
opts...,
|
||||
)
|
||||
|
||||
return auth, nil
|
||||
}
|
||||
|
||||
func getRandomBytes(n int) ([]byte, error) {
|
||||
data := make([]byte, n)
|
||||
|
||||
read, err := rand.Read(data)
|
||||
if err != nil {
|
||||
return nil, errors.WithStack(err)
|
||||
}
|
||||
|
||||
if read != n {
|
||||
return nil, errors.Errorf("could not read %d bytes", n)
|
||||
}
|
||||
|
||||
return data, nil
|
||||
}
|
27
internal/setup/http_server.go
Normal file
27
internal/setup/http_server.go
Normal file
@ -0,0 +1,27 @@
|
||||
package setup
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"forge.cadoles.com/wpetit/clearcase/internal/config"
|
||||
"forge.cadoles.com/wpetit/clearcase/internal/http"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
func NewHTTPServerFromConfig(ctx context.Context, conf *config.Config) (*http.Server, error) {
|
||||
// Configure Web UI handler
|
||||
webui, err := NewWebUIHandlerFromConfig(ctx, conf)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not configure webui handler from config")
|
||||
}
|
||||
|
||||
// Create HTTP server
|
||||
|
||||
server := http.NewServer(
|
||||
webui,
|
||||
http.WithAddress(conf.HTTP.Address),
|
||||
http.WithBaseURL(conf.HTTP.BaseURL),
|
||||
)
|
||||
|
||||
return server, nil
|
||||
}
|
12
internal/setup/issue_handler.go
Normal file
12
internal/setup/issue_handler.go
Normal file
@ -0,0 +1,12 @@
|
||||
package setup
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"forge.cadoles.com/wpetit/clearcase/internal/config"
|
||||
"forge.cadoles.com/wpetit/clearcase/internal/http/handler/webui/issue"
|
||||
)
|
||||
|
||||
func NewIssueHandlerFromConfig(ctx context.Context, conf *config.Config) (*issue.Handler, error) {
|
||||
return issue.NewHandler(), nil
|
||||
}
|
44
internal/setup/registry.go
Normal file
44
internal/setup/registry.go
Normal file
@ -0,0 +1,44 @@
|
||||
package setup
|
||||
|
||||
import (
|
||||
"net/url"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
var ErrNotRegistered = errors.New("not registered")
|
||||
|
||||
type Factory[T any] func(u *url.URL) (T, error)
|
||||
|
||||
type Registry[T any] struct {
|
||||
mappings map[string]Factory[T]
|
||||
}
|
||||
|
||||
func (r *Registry[T]) Register(scheme string, factory Factory[T]) {
|
||||
r.mappings[scheme] = factory
|
||||
}
|
||||
|
||||
func (r *Registry[T]) From(rawURL string) (T, error) {
|
||||
u, err := url.Parse(rawURL)
|
||||
if err != nil {
|
||||
return *new(T), errors.WithStack(err)
|
||||
}
|
||||
|
||||
factory, exists := r.mappings[u.Scheme]
|
||||
if !exists {
|
||||
return *new(T), errors.Wrapf(ErrNotRegistered, "scheme '%s' not found", u.Scheme)
|
||||
}
|
||||
|
||||
value, err := factory(u)
|
||||
if err != nil {
|
||||
return *new(T), errors.WithStack(err)
|
||||
}
|
||||
|
||||
return value, nil
|
||||
}
|
||||
|
||||
func NewRegistry[T any]() *Registry[T] {
|
||||
return &Registry[T]{
|
||||
mappings: make(map[string]Factory[T]),
|
||||
}
|
||||
}
|
48
internal/setup/webui_handler.go
Normal file
48
internal/setup/webui_handler.go
Normal file
@ -0,0 +1,48 @@
|
||||
package setup
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"forge.cadoles.com/wpetit/clearcase/internal/config"
|
||||
"forge.cadoles.com/wpetit/clearcase/internal/http/handler/webui"
|
||||
"forge.cadoles.com/wpetit/clearcase/internal/http/handler/webui/common"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
func NewWebUIHandlerFromConfig(ctx context.Context, conf *config.Config) (*webui.Handler, error) {
|
||||
opts := make([]webui.OptionFunc, 0)
|
||||
|
||||
// Configure auth handler
|
||||
authHandler, err := NewAuthHandlerFromConfig(ctx, conf)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not configure auth handler from config")
|
||||
}
|
||||
|
||||
authMiddleware := authHandler.Middleware()
|
||||
|
||||
opts = append(opts, webui.WithMount("/auth/", authHandler))
|
||||
|
||||
// Configure issue handler
|
||||
issueHandler, err := NewIssueHandlerFromConfig(ctx, conf)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not configure explorer handler from config")
|
||||
}
|
||||
|
||||
opts = append(opts, webui.WithMount("/", authMiddleware(issueHandler)))
|
||||
|
||||
// Configure common handler
|
||||
commonHandler, err := NewCommonHandlerFromConfig(ctx, conf)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not configure common handler from config")
|
||||
}
|
||||
|
||||
opts = append(opts, webui.WithMount("/assets/", commonHandler))
|
||||
|
||||
handler := webui.NewHandler(opts...)
|
||||
|
||||
return handler, nil
|
||||
}
|
||||
|
||||
func NewCommonHandlerFromConfig(ctx context.Context, conf *config.Config) (*common.Handler, error) {
|
||||
return common.NewHandler(), nil
|
||||
}
|
Reference in New Issue
Block a user