Skip to content

Commit

Permalink
Merge branch 'main' into label-action
Browse files Browse the repository at this point in the history
  • Loading branch information
kodiakhq[bot] authored Jun 7, 2024
2 parents be09c55 + 9d4a6ef commit 432445b
Show file tree
Hide file tree
Showing 26 changed files with 491 additions and 67 deletions.
3 changes: 3 additions & 0 deletions examples/proxy/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
### Running Flipt behind the reverse proxy with custom path

Use `[email protected]` and `password` for authentication in Dex
29 changes: 29 additions & 0 deletions examples/proxy/dex.config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
issuer: http://localhost:5556/dex

storage:
type: sqlite3
config:
file: /var/dex/dex.db

web:
http: 0.0.0.0:5556

staticClients:
- id: example-app
redirectURIs:
- http://localhost:8080/flipt/auth/v1/method/oidc/dex/callback
name: Example App
secret: ZXhhbXBsZS1hcHAtc2VjcmV0

connectors:
- type: mockCallback
id: mock
name: Example

enablePasswordDB: true

staticPasswords:
- email: "[email protected]"
hash: "$2a$10$2b2cU8CPhOTaGrs1HRQuAueS7JTT5ZHsHSzYiFPm1leZck7Mc8T4W" #password
username: "admin"
userID: "08a8684b-db88-4b73-90a9-3cd1661f5466"
14 changes: 12 additions & 2 deletions examples/proxy/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,23 @@ services:
- flipt_network
volumes:
- ./features.yml:/opt/features.yml:ro
- ./flipt.config.yml:/etc/flipt/config/default.yml:ro
- ./hosts.txt:/etc/hosts:ro
healthcheck:
test: wget --no-verbose --tries=1 --spider http://localhost:8080/health || exit 1
test: wget --no-verbose --tries=1 --spider http://127.0.0.1:8080/health || exit 1

localhost:
image: ghcr.io/dexidp/dex:latest-distroless
ports:
- "5556:5556"
networks:
- flipt_network
volumes:
- ./dex.config.yml:/etc/dex/config.docker.yaml
nginx:
image: nginx:alpine
ports:
- "9999:80"
- "8080:80"
networks:
- flipt_network
volumes:
Expand Down
18 changes: 18 additions & 0 deletions examples/proxy/flipt.config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
authentication:
required: true
session:
domain: "localhost:8080"
secure: false
methods:
oidc:
enabled: true
email_matches:
- ^.*@example.com$
providers:
dex:
issuer_url: http://localhost:5556/dex
client_id: example-app
client_secret: ZXhhbXBsZS1hcHAtc2VjcmV0
redirect_address: http://localhost:8080/flipt
scopes:
- email
Empty file added examples/proxy/hosts.txt
Empty file.
1 change: 1 addition & 0 deletions examples/proxy/nginx.conf
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ server {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Prefix /flipt;
proxy_buffering on;

# rewrite
Expand Down
2 changes: 1 addition & 1 deletion internal/cleanup/cleanup.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ func NewAuthenticationService(logger *zap.Logger, lock oplock.Service, store aut
func (s *AuthenticationService) Run(ctx context.Context) {
ctx, s.cancel = context.WithCancel(ctx)

for _, info := range s.config.Methods.AllMethods() {
for _, info := range s.config.Methods.AllMethods(ctx) {
logger := s.logger.With(zap.Stringer("method", info.Method))
if info.Cleanup == nil {
if info.Enabled {
Expand Down
4 changes: 2 additions & 2 deletions internal/cleanup/cleanup_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ func TestCleanup(t *testing.T) {
)

// enable all methods and set their cleanup configuration
for _, info := range authConfig.Methods.AllMethods() {
for _, info := range authConfig.Methods.AllMethods(ctx) {
info.Enable(t)
info.SetCleanup(t, config.AuthenticationCleanupSchedule{
Interval: time.Second,
Expand Down Expand Up @@ -64,7 +64,7 @@ func TestCleanup(t *testing.T) {
assert.Equal(t, storedAuth, retrievedAuth)
})

for _, info := range authConfig.Methods.AllMethods() {
for _, info := range authConfig.Methods.AllMethods(ctx) {
info := info
if !info.RequiresDatabase {
continue
Expand Down
2 changes: 1 addition & 1 deletion internal/cmd/authn.go
Original file line number Diff line number Diff line change
Expand Up @@ -333,7 +333,7 @@ func authenticationHTTPMount(
}

if cfg.SessionEnabled() {
muxOpts = append(muxOpts, runtime.WithMetadata(method.ForwardCookies))
muxOpts = append(muxOpts, runtime.WithMetadata(method.ForwardCookies), runtime.WithMetadata(method.ForwardPrefix))

methodMiddleware := method.NewHTTPMiddleware(cfg.Session)
muxOpts = append(muxOpts, runtime.WithForwardResponseOption(methodMiddleware.ForwardResponseOption))
Expand Down
2 changes: 2 additions & 0 deletions internal/cmd/http.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"go.flipt.io/flipt/internal/config"
"go.flipt.io/flipt/internal/gateway"
"go.flipt.io/flipt/internal/info"
"go.flipt.io/flipt/internal/server/authn/method"
"go.flipt.io/flipt/rpc/flipt"
"go.flipt.io/flipt/rpc/flipt/analytics"
"go.flipt.io/flipt/rpc/flipt/evaluation"
Expand Down Expand Up @@ -176,6 +177,7 @@ func NewHTTPServer(
conn,
meta.RegisterMetadataServiceHandler,
),
runtime.WithMetadata(method.ForwardPrefix),
))
})
})
Expand Down
75 changes: 47 additions & 28 deletions internal/config/authentication.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
package config

import (
"context"
"fmt"
"net/url"
"os"
"path"
"slices"
"strings"
"testing"
Expand Down Expand Up @@ -65,7 +67,7 @@ func (c AuthenticationConfig) Enabled() bool {
return true
}

for _, info := range c.Methods.AllMethods() {
for _, info := range c.Methods.AllMethods(context.Background()) {
if info.Enabled {
return true
}
Expand All @@ -77,7 +79,7 @@ func (c AuthenticationConfig) Enabled() bool {
// RequiresDatabase returns true if any of the enabled authentication
// methods requires a database connection
func (c AuthenticationConfig) RequiresDatabase() bool {
for _, info := range c.Methods.AllMethods() {
for _, info := range c.Methods.AllMethods(context.Background()) {
if info.Enabled && info.RequiresDatabase {
return true
}
Expand All @@ -96,7 +98,7 @@ func (c AuthenticationConfig) IsZero() bool {
// It returns true given at-least 1 method is enabled and it's associated schedule
// has been configured (non-nil).
func (c AuthenticationConfig) ShouldRunCleanup() (shouldCleanup bool) {
for _, info := range c.Methods.AllMethods() {
for _, info := range c.Methods.AllMethods(context.Background()) {
shouldCleanup = shouldCleanup || info.RequiresCleanup()
}

Expand All @@ -107,7 +109,7 @@ func (c *AuthenticationConfig) setDefaults(v *viper.Viper) error {
methods := map[string]any{}

// set default for each methods
for _, info := range c.Methods.AllMethods() {
for _, info := range c.Methods.AllMethods(context.Background()) {
method := map[string]any{"enabled": false}
// if the method has been enabled then set the defaults
// for its cleanup strategy
Expand Down Expand Up @@ -139,7 +141,7 @@ func (c *AuthenticationConfig) setDefaults(v *viper.Viper) error {

func (c *AuthenticationConfig) SessionEnabled() bool {
var sessionEnabled bool
for _, info := range c.Methods.AllMethods() {
for _, info := range c.Methods.AllMethods(context.Background()) {
sessionEnabled = sessionEnabled || (info.Enabled && info.SessionCompatible)
}

Expand All @@ -149,7 +151,7 @@ func (c *AuthenticationConfig) SessionEnabled() bool {
func (c *AuthenticationConfig) validate() error {
var sessionEnabled bool

for _, info := range c.Methods.AllMethods() {
for _, info := range c.Methods.AllMethods(context.Background()) {
if !info.RequiresCleanup() {
continue
}
Expand Down Expand Up @@ -189,7 +191,7 @@ func (c *AuthenticationConfig) validate() error {
c.Session.Domain = host
}

for _, info := range c.Methods.AllMethods() {
for _, info := range c.Methods.AllMethods(context.Background()) {
if err := info.validate(); err != nil {
return err
}
Expand Down Expand Up @@ -251,21 +253,32 @@ type AuthenticationMethods struct {
}

// AllMethods returns all the AuthenticationMethod instances available.
func (a *AuthenticationMethods) AllMethods() []StaticAuthenticationMethodInfo {
func (a *AuthenticationMethods) AllMethods(ctx context.Context) []StaticAuthenticationMethodInfo {
return []StaticAuthenticationMethodInfo{
a.Token.info(),
a.Github.info(),
a.OIDC.info(),
a.Kubernetes.info(),
a.JWT.info(),
a.Cloud.info(),
a.Token.info(ctx),
a.Github.info(ctx),
a.OIDC.info(ctx),
a.Kubernetes.info(ctx),
a.JWT.info(ctx),
a.Cloud.info(ctx),
}
}

type forwardPrefixContext struct{}

func WithForwardPrefix(ctx context.Context, prefix string) context.Context {
return context.WithValue(ctx, forwardPrefixContext{}, prefix)
}

func getForwardPrefix(ctx context.Context) string {
prefix, _ := ctx.Value(forwardPrefixContext{}).(string)
return prefix
}

// EnabledMethods returns all the AuthenticationMethod instances that have been enabled.
func (a *AuthenticationMethods) EnabledMethods() []StaticAuthenticationMethodInfo {
var enabled []StaticAuthenticationMethodInfo
for _, info := range a.AllMethods() {
for _, info := range a.AllMethods(context.Background()) {
if info.Enabled {
enabled = append(enabled, info)
}
Expand Down Expand Up @@ -329,7 +342,7 @@ func (a AuthenticationMethodInfo) Name() string {
// methods properties.
type AuthenticationMethodInfoProvider interface {
setDefaults(map[string]any)
info() AuthenticationMethodInfo
info(context.Context) AuthenticationMethodInfo
validate() error
}

Expand All @@ -349,9 +362,9 @@ func (a *AuthenticationMethod[C]) setDefaults(defaults map[string]any) {
a.Method.setDefaults(defaults)
}

func (a *AuthenticationMethod[C]) info() StaticAuthenticationMethodInfo {
func (a *AuthenticationMethod[C]) info(ctx context.Context) StaticAuthenticationMethodInfo {
return StaticAuthenticationMethodInfo{
AuthenticationMethodInfo: a.Method.info(),
AuthenticationMethodInfo: a.Method.info(ctx),
Enabled: a.Enabled,
Cleanup: a.Cleanup,

Expand Down Expand Up @@ -379,7 +392,7 @@ type AuthenticationMethodCloudConfig struct{}
func (a AuthenticationMethodCloudConfig) setDefaults(map[string]any) {}

// info describes properties of the authentication method "cloud".
func (a AuthenticationMethodCloudConfig) info() AuthenticationMethodInfo {
func (a AuthenticationMethodCloudConfig) info(_ context.Context) AuthenticationMethodInfo {
return AuthenticationMethodInfo{
Method: auth.Method_METHOD_CLOUD,
SessionCompatible: true,
Expand All @@ -400,7 +413,7 @@ type AuthenticationMethodTokenConfig struct {
func (a AuthenticationMethodTokenConfig) setDefaults(map[string]any) {}

// info describes properties of the authentication method "token".
func (a AuthenticationMethodTokenConfig) info() AuthenticationMethodInfo {
func (a AuthenticationMethodTokenConfig) info(_ context.Context) AuthenticationMethodInfo {
return AuthenticationMethodInfo{
Method: auth.Method_METHOD_TOKEN,
SessionCompatible: false,
Expand All @@ -427,7 +440,7 @@ type AuthenticationMethodOIDCConfig struct {
func (a AuthenticationMethodOIDCConfig) setDefaults(map[string]any) {}

// info describes properties of the authentication method "oidc".
func (a AuthenticationMethodOIDCConfig) info() AuthenticationMethodInfo {
func (a AuthenticationMethodOIDCConfig) info(ctx context.Context) AuthenticationMethodInfo {
info := AuthenticationMethodInfo{
Method: auth.Method_METHOD_OIDC,
SessionCompatible: true,
Expand All @@ -443,8 +456,14 @@ func (a AuthenticationMethodOIDCConfig) info() AuthenticationMethodInfo {
// to the UI via the /auth/v1/method endpoint
for provider := range a.Providers {
providers[provider] = map[string]any{
"authorize_url": fmt.Sprintf("/auth/v1/method/oidc/%s/authorize", provider),
"callback_url": fmt.Sprintf("/auth/v1/method/oidc/%s/callback", provider),
"authorize_url": path.Join(
getForwardPrefix(ctx),
fmt.Sprintf("/auth/v1/method/oidc/%s/authorize", provider),
),
"callback_url": path.Join(
getForwardPrefix(ctx),
fmt.Sprintf("/auth/v1/method/oidc/%s/callback", provider),
),
}
}

Expand Down Expand Up @@ -520,7 +539,7 @@ func (a AuthenticationMethodKubernetesConfig) setDefaults(defaults map[string]an
}

// info describes properties of the authentication method "kubernetes".
func (a AuthenticationMethodKubernetesConfig) info() AuthenticationMethodInfo {
func (a AuthenticationMethodKubernetesConfig) info(_ context.Context) AuthenticationMethodInfo {
return AuthenticationMethodInfo{
Method: auth.Method_METHOD_KUBERNETES,
SessionCompatible: false,
Expand All @@ -546,7 +565,7 @@ type AuthenticationMethodGithubConfig struct {
func (a AuthenticationMethodGithubConfig) setDefaults(defaults map[string]any) {}

// info describes properties of the authentication method "github".
func (a AuthenticationMethodGithubConfig) info() AuthenticationMethodInfo {
func (a AuthenticationMethodGithubConfig) info(ctx context.Context) AuthenticationMethodInfo {
info := AuthenticationMethodInfo{
Method: auth.Method_METHOD_GITHUB,
SessionCompatible: true,
Expand All @@ -555,8 +574,8 @@ func (a AuthenticationMethodGithubConfig) info() AuthenticationMethodInfo {

metadata := make(map[string]any)

metadata["authorize_url"] = "/auth/v1/method/github/authorize"
metadata["callback_url"] = "/auth/v1/method/github/callback"
metadata["authorize_url"] = path.Join(getForwardPrefix(ctx), "/auth/v1/method/github/authorize")
metadata["callback_url"] = path.Join(getForwardPrefix(ctx), "/auth/v1/method/github/callback")

info.Metadata, _ = structpb.NewStruct(metadata)

Expand Down Expand Up @@ -620,7 +639,7 @@ type AuthenticationMethodJWTConfig struct {
func (a AuthenticationMethodJWTConfig) setDefaults(map[string]any) {}

// info describes properties of the authentication method "jwt".
func (a AuthenticationMethodJWTConfig) info() AuthenticationMethodInfo {
func (a AuthenticationMethodJWTConfig) info(_ context.Context) AuthenticationMethodInfo {
return AuthenticationMethodInfo{
Method: auth.Method_METHOD_JWT,
SessionCompatible: false,
Expand Down
Loading

0 comments on commit 432445b

Please sign in to comment.