This repository has been archived on 2024-05-31. You can view files and clone it, but cannot push or open issues or pull requests.
authentik/outpost/pkg/proxy/api_bundle.go

166 lines
4.9 KiB
Go
Raw Permalink Normal View History

package proxy
2020-09-02 22:04:12 +00:00
import (
"context"
"crypto/tls"
"net"
"net/http"
"net/url"
"os"
2020-09-19 09:32:21 +00:00
"strings"
2020-09-02 22:04:12 +00:00
"github.com/jinzhu/copier"
"github.com/justinas/alice"
"github.com/oauth2-proxy/oauth2-proxy/pkg/apis/options"
"github.com/oauth2-proxy/oauth2-proxy/pkg/middleware"
"github.com/oauth2-proxy/oauth2-proxy/pkg/validation"
log "github.com/sirupsen/logrus"
2021-01-16 20:45:24 +00:00
"goauthentik.io/outpost/pkg/client/crypto"
"goauthentik.io/outpost/pkg/models"
2020-09-02 22:04:12 +00:00
)
type providerBundle struct {
http.Handler
s *Server
proxy *OAuthProxy
2020-09-02 22:04:12 +00:00
Host string
cert *tls.Certificate
log *log.Entry
2020-09-02 22:04:12 +00:00
}
2021-04-29 16:17:10 +00:00
func intToPointer(i int) *int {
return &i
}
2020-09-02 22:04:12 +00:00
func (pb *providerBundle) prepareOpts(provider *models.ProxyOutpostConfig) *options.Options {
externalHost, err := url.Parse(*provider.ExternalHost)
if err != nil {
log.WithError(err).Warning("Failed to parse URL, skipping provider")
return nil
}
providerOpts := &options.Options{}
err = copier.Copy(&providerOpts, getCommonOptions())
if err != nil {
log.WithError(err).Warning("Failed to copy options, skipping provider")
return nil
}
2020-09-02 22:04:12 +00:00
providerOpts.ClientID = provider.ClientID
providerOpts.ClientSecret = provider.ClientSecret
providerOpts.Cookie.Secret = provider.CookieSecret
providerOpts.Cookie.Secure = externalHost.Scheme == "https"
providerOpts.SkipOIDCDiscovery = true
providerOpts.OIDCIssuerURL = *provider.OidcConfiguration.Issuer
providerOpts.LoginURL = *provider.OidcConfiguration.AuthorizationEndpoint
providerOpts.RedeemURL = *provider.OidcConfiguration.TokenEndpoint
providerOpts.OIDCJwksURL = *provider.OidcConfiguration.JwksURI
providerOpts.ProfileURL = *provider.OidcConfiguration.UserinfoEndpoint
if provider.SkipPathRegex != "" {
skipRegexes := strings.Split(provider.SkipPathRegex, "\n")
providerOpts.SkipAuthRegex = skipRegexes
}
2020-09-19 09:32:21 +00:00
2021-04-29 16:17:10 +00:00
if provider.ForwardAuthMode {
providerOpts.UpstreamServers = []options.Upstream{
{
ID: "static",
Static: true,
StaticCode: intToPointer(202),
Path: "/",
},
}
} else {
providerOpts.UpstreamServers = []options.Upstream{
{
ID: "default",
URI: provider.InternalHost,
Path: "/",
InsecureSkipTLSVerify: !provider.InternalHostSslValidation,
2021-04-29 16:17:10 +00:00
},
}
2020-09-02 22:04:12 +00:00
}
if provider.Certificate != nil {
pb.log.WithField("provider", provider.Name).Debug("Enabling TLS")
cert, err := pb.s.ak.Client.Crypto.CryptoCertificatekeypairsViewCertificate(&crypto.CryptoCertificatekeypairsViewCertificateParams{
2020-09-02 22:04:12 +00:00
Context: context.Background(),
KpUUID: *provider.Certificate,
}, pb.s.ak.Auth)
2020-09-02 22:04:12 +00:00
if err != nil {
pb.log.WithField("provider", provider.Name).WithError(err).Warning("Failed to fetch certificate")
2020-09-02 22:04:12 +00:00
return providerOpts
}
key, err := pb.s.ak.Client.Crypto.CryptoCertificatekeypairsViewPrivateKey(&crypto.CryptoCertificatekeypairsViewPrivateKeyParams{
Context: context.Background(),
KpUUID: *provider.Certificate,
}, pb.s.ak.Auth)
if err != nil {
pb.log.WithField("provider", provider.Name).WithError(err).Warning("Failed to fetch private key")
return providerOpts
}
x509cert, err := tls.X509KeyPair([]byte(cert.Payload.Data), []byte(key.Payload.Data))
2020-09-02 22:04:12 +00:00
if err != nil {
pb.log.WithField("provider", provider.Name).WithError(err).Warning("Failed to parse certificate")
2020-09-02 22:04:12 +00:00
return providerOpts
}
pb.cert = &x509cert
pb.log.WithField("provider", provider.Name).Debug("Loaded certificates")
2020-09-02 22:04:12 +00:00
}
return providerOpts
}
func (pb *providerBundle) Build(provider *models.ProxyOutpostConfig) {
opts := pb.prepareOpts(provider)
chain := alice.New()
if opts.ForceHTTPS {
_, httpsPort, err := net.SplitHostPort(opts.HTTPSAddress)
if err != nil {
log.Fatalf("FATAL: invalid HTTPS address %q: %v", opts.HTTPAddress, err)
}
chain = chain.Append(middleware.NewRedirectToHTTPS(httpsPort))
}
healthCheckPaths := []string{opts.PingPath}
healthCheckUserAgents := []string{opts.PingUserAgent}
if opts.GCPHealthChecks {
healthCheckPaths = append(healthCheckPaths, "/liveness_check", "/readiness_check")
healthCheckUserAgents = append(healthCheckUserAgents, "GoogleHC/1.0")
}
// To silence logging of health checks, register the health check handler before
// the logging handler
if opts.Logging.SilencePing {
chain = chain.Append(middleware.NewHealthCheck(healthCheckPaths, healthCheckUserAgents), LoggingHandler)
} else {
chain = chain.Append(LoggingHandler, middleware.NewHealthCheck(healthCheckPaths, healthCheckUserAgents))
}
err := validation.Validate(opts)
if err != nil {
log.Printf("%s", err)
os.Exit(1)
}
oauthproxy, err := NewOAuthProxy(opts, provider)
2020-09-02 22:04:12 +00:00
if err != nil {
log.Errorf("ERROR: Failed to initialise OAuth2 Proxy: %v", err)
os.Exit(1)
}
if provider.BasicAuthEnabled {
oauthproxy.SetBasicAuth = true
oauthproxy.BasicAuthUserAttribute = provider.BasicAuthUserAttribute
oauthproxy.BasicAuthPasswordAttribute = provider.BasicAuthPasswordAttribute
}
2020-09-02 22:04:12 +00:00
pb.proxy = oauthproxy
pb.Handler = chain.Then(oauthproxy)
}