mirror of
https://github.com/openziti/zrok.git
synced 2024-11-22 08:03:49 +01:00
Merge branch 'main' into self-service-password
This commit is contained in:
commit
56ed13d96a
@ -6,6 +6,8 @@ FEATURE: Added self service password change. There is a new tab in the `zrok` co
|
|||||||
|
|
||||||
FEATURE: The web console now supports revoking your current account token and generating a new one (https://github.com/openziti/zrok/issues/191)
|
FEATURE: The web console now supports revoking your current account token and generating a new one (https://github.com/openziti/zrok/issues/191)
|
||||||
|
|
||||||
|
CHANGE: When specifying OAuth configuration for public shares from the `zrok share public` or `zrok reserve` public commands, the flags and functionality for restricting the allowed email addresses of the authenticating users has changed. The old flag was `--oauth-email-domains`, which took a string value that needed to be contained in the user's email address. The new flag is `--oauth-email-address-patterns`, which accepts a glob-style filter, using https://github.com/gobwas/glob (https://github.com/openziti/zrok/issues/413)
|
||||||
|
|
||||||
CHANGE: Creating a reserved share checks for token collision and returns a more appropriate error message (https://github.com/openziti/zrok/issues/531)
|
CHANGE: Creating a reserved share checks for token collision and returns a more appropriate error message (https://github.com/openziti/zrok/issues/531)
|
||||||
|
|
||||||
CHANGE: Update UI to add a 'true' value on `reserved` boolean (https://github.com/openziti/zrok/issues/443)
|
CHANGE: Update UI to add a 'true' value on `reserved` boolean (https://github.com/openziti/zrok/issues/443)
|
||||||
|
@ -18,15 +18,15 @@ func init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type reserveCommand struct {
|
type reserveCommand struct {
|
||||||
uniqueName string
|
uniqueName string
|
||||||
basicAuth []string
|
basicAuth []string
|
||||||
frontendSelection []string
|
frontendSelection []string
|
||||||
backendMode string
|
backendMode string
|
||||||
jsonOutput bool
|
jsonOutput bool
|
||||||
oauthProvider string
|
oauthProvider string
|
||||||
oauthEmailDomains []string
|
oauthEmailAddressPatterns []string
|
||||||
oauthCheckInterval time.Duration
|
oauthCheckInterval time.Duration
|
||||||
cmd *cobra.Command
|
cmd *cobra.Command
|
||||||
}
|
}
|
||||||
|
|
||||||
func newReserveCommand() *reserveCommand {
|
func newReserveCommand() *reserveCommand {
|
||||||
@ -42,7 +42,7 @@ func newReserveCommand() *reserveCommand {
|
|||||||
cmd.Flags().BoolVarP(&command.jsonOutput, "json-output", "j", false, "Emit JSON describing the created reserved share")
|
cmd.Flags().BoolVarP(&command.jsonOutput, "json-output", "j", false, "Emit JSON describing the created reserved share")
|
||||||
cmd.Flags().StringArrayVar(&command.basicAuth, "basic-auth", []string{}, "Basic authentication users (<username:password>,...)")
|
cmd.Flags().StringArrayVar(&command.basicAuth, "basic-auth", []string{}, "Basic authentication users (<username:password>,...)")
|
||||||
cmd.Flags().StringVar(&command.oauthProvider, "oauth-provider", "", "Enable OAuth provider [google, github]")
|
cmd.Flags().StringVar(&command.oauthProvider, "oauth-provider", "", "Enable OAuth provider [google, github]")
|
||||||
cmd.Flags().StringArrayVar(&command.oauthEmailDomains, "oauth-email-domains", []string{}, "Allow only these email domains to authenticate via OAuth")
|
cmd.Flags().StringArrayVar(&command.oauthEmailAddressPatterns, "oauth-email-address-patterns", []string{}, "Allow only these email domains to authenticate via OAuth")
|
||||||
cmd.Flags().DurationVar(&command.oauthCheckInterval, "oauth-check-interval", 3*time.Hour, "Maximum lifetime for OAuth authentication; reauthenticate after expiry")
|
cmd.Flags().DurationVar(&command.oauthCheckInterval, "oauth-check-interval", 3*time.Hour, "Maximum lifetime for OAuth authentication; reauthenticate after expiry")
|
||||||
cmd.MarkFlagsMutuallyExclusive("basic-auth", "oauth-provider")
|
cmd.MarkFlagsMutuallyExclusive("basic-auth", "oauth-provider")
|
||||||
|
|
||||||
@ -139,7 +139,7 @@ func (cmd *reserveCommand) run(_ *cobra.Command, args []string) {
|
|||||||
tui.Error("--oauth-provider only supported for public shares", nil)
|
tui.Error("--oauth-provider only supported for public shares", nil)
|
||||||
}
|
}
|
||||||
req.OauthProvider = cmd.oauthProvider
|
req.OauthProvider = cmd.oauthProvider
|
||||||
req.OauthEmailDomains = cmd.oauthEmailDomains
|
req.OauthEmailAddressPatterns = cmd.oauthEmailAddressPatterns
|
||||||
req.OauthAuthorizationCheckInterval = cmd.oauthCheckInterval
|
req.OauthAuthorizationCheckInterval = cmd.oauthCheckInterval
|
||||||
}
|
}
|
||||||
shr, err := sdk.CreateShare(env, req)
|
shr, err := sdk.CreateShare(env, req)
|
||||||
|
@ -3,6 +3,7 @@ package main
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
tea "github.com/charmbracelet/bubbletea"
|
tea "github.com/charmbracelet/bubbletea"
|
||||||
|
"github.com/gobwas/glob"
|
||||||
"github.com/openziti/zrok/endpoints"
|
"github.com/openziti/zrok/endpoints"
|
||||||
drive "github.com/openziti/zrok/endpoints/drive"
|
drive "github.com/openziti/zrok/endpoints/drive"
|
||||||
"github.com/openziti/zrok/endpoints/proxy"
|
"github.com/openziti/zrok/endpoints/proxy"
|
||||||
@ -24,15 +25,15 @@ func init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type sharePublicCommand struct {
|
type sharePublicCommand struct {
|
||||||
basicAuth []string
|
basicAuth []string
|
||||||
frontendSelection []string
|
frontendSelection []string
|
||||||
backendMode string
|
backendMode string
|
||||||
headless bool
|
headless bool
|
||||||
insecure bool
|
insecure bool
|
||||||
oauthProvider string
|
oauthProvider string
|
||||||
oauthEmailDomains []string
|
oauthEmailAddressPatterns []string
|
||||||
oauthCheckInterval time.Duration
|
oauthCheckInterval time.Duration
|
||||||
cmd *cobra.Command
|
cmd *cobra.Command
|
||||||
}
|
}
|
||||||
|
|
||||||
func newSharePublicCommand() *sharePublicCommand {
|
func newSharePublicCommand() *sharePublicCommand {
|
||||||
@ -49,7 +50,7 @@ func newSharePublicCommand() *sharePublicCommand {
|
|||||||
|
|
||||||
cmd.Flags().StringArrayVar(&command.basicAuth, "basic-auth", []string{}, "Basic authentication users (<username:password>,...)")
|
cmd.Flags().StringArrayVar(&command.basicAuth, "basic-auth", []string{}, "Basic authentication users (<username:password>,...)")
|
||||||
cmd.Flags().StringVar(&command.oauthProvider, "oauth-provider", "", "Enable OAuth provider [google, github]")
|
cmd.Flags().StringVar(&command.oauthProvider, "oauth-provider", "", "Enable OAuth provider [google, github]")
|
||||||
cmd.Flags().StringArrayVar(&command.oauthEmailDomains, "oauth-email-domains", []string{}, "Allow only these email domains to authenticate via OAuth")
|
cmd.Flags().StringArrayVar(&command.oauthEmailAddressPatterns, "oauth-email-address-patterns", []string{}, "Allow only these email domain globs to authenticate via OAuth")
|
||||||
cmd.Flags().DurationVar(&command.oauthCheckInterval, "oauth-check-interval", 3*time.Hour, "Maximum lifetime for OAuth authentication; reauthenticate after expiry")
|
cmd.Flags().DurationVar(&command.oauthCheckInterval, "oauth-check-interval", 3*time.Hour, "Maximum lifetime for OAuth authentication; reauthenticate after expiry")
|
||||||
cmd.MarkFlagsMutuallyExclusive("basic-auth", "oauth-provider")
|
cmd.MarkFlagsMutuallyExclusive("basic-auth", "oauth-provider")
|
||||||
|
|
||||||
@ -114,8 +115,18 @@ func (cmd *sharePublicCommand) run(_ *cobra.Command, args []string) {
|
|||||||
}
|
}
|
||||||
if cmd.oauthProvider != "" {
|
if cmd.oauthProvider != "" {
|
||||||
req.OauthProvider = cmd.oauthProvider
|
req.OauthProvider = cmd.oauthProvider
|
||||||
req.OauthEmailDomains = cmd.oauthEmailDomains
|
req.OauthEmailAddressPatterns = cmd.oauthEmailAddressPatterns
|
||||||
req.OauthAuthorizationCheckInterval = cmd.oauthCheckInterval
|
req.OauthAuthorizationCheckInterval = cmd.oauthCheckInterval
|
||||||
|
|
||||||
|
for _, g := range cmd.oauthEmailAddressPatterns {
|
||||||
|
_, err := glob.Compile(g)
|
||||||
|
if err != nil {
|
||||||
|
if !panicInstead {
|
||||||
|
tui.Error(fmt.Sprintf("unable to create share, invalid oauth email glob (%v)", g), err)
|
||||||
|
}
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
shr, err := sdk.CreateShare(root, req)
|
shr, err := sdk.CreateShare(root, req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -4,6 +4,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"crypto/md5"
|
"crypto/md5"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/gobwas/glob"
|
||||||
"github.com/golang-jwt/jwt/v5"
|
"github.com/golang-jwt/jwt/v5"
|
||||||
"github.com/openziti/sdk-golang/ziti"
|
"github.com/openziti/sdk-golang/ziti"
|
||||||
"github.com/openziti/zrok/endpoints"
|
"github.com/openziti/zrok/endpoints"
|
||||||
@ -266,21 +267,33 @@ func authHandler(handler http.Handler, pcfg *Config, key []byte, ctx ziti.Contex
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if validDomains, found := oauthCfg.(map[string]interface{})["email_domains"]; found {
|
if validEmailAddressPatterns, found := oauthCfg.(map[string]interface{})["email_domains"]; found {
|
||||||
if castedDomains, ok := validDomains.([]interface{}); !ok {
|
if castedPatterns, ok := validEmailAddressPatterns.([]interface{}); !ok {
|
||||||
logrus.Error("invalid email domain format")
|
logrus.Error("invalid email pattern array format")
|
||||||
return
|
return
|
||||||
} else {
|
} else {
|
||||||
if len(castedDomains) > 0 {
|
if len(castedPatterns) > 0 {
|
||||||
found := false
|
found := false
|
||||||
for _, domain := range castedDomains {
|
for _, pattern := range castedPatterns {
|
||||||
if strings.HasSuffix(claims.Email, domain.(string)) {
|
if castedPattern, ok := pattern.(string); ok {
|
||||||
found = true
|
match, err := glob.Compile(castedPattern)
|
||||||
break
|
if err != nil {
|
||||||
|
logrus.Errorf("invalid email address pattern glob '%v': %v", pattern.(string), err)
|
||||||
|
unauthorizedUi.WriteUnauthorized(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if match.Match(claims.Email) {
|
||||||
|
found = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
logrus.Errorf("invalid email address pattern '%v'", pattern)
|
||||||
|
unauthorizedUi.WriteUnauthorized(w)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !found {
|
if !found {
|
||||||
logrus.Warnf("invalid email domain")
|
logrus.Warnf("unauthorized email '%v' for '%v'", claims.Email, shrToken)
|
||||||
unauthorizedUi.WriteUnauthorized(w)
|
unauthorizedUi.WriteUnauthorized(w)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
1
go.mod
1
go.mod
@ -106,6 +106,7 @@ require (
|
|||||||
github.com/go-resty/resty/v2 v2.11.0 // indirect
|
github.com/go-resty/resty/v2 v2.11.0 // indirect
|
||||||
github.com/go-sql-driver/mysql v1.7.1 // indirect
|
github.com/go-sql-driver/mysql v1.7.1 // indirect
|
||||||
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect
|
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect
|
||||||
|
github.com/gobwas/glob v0.2.3 // indirect
|
||||||
github.com/golang/glog v1.1.2 // indirect
|
github.com/golang/glog v1.1.2 // indirect
|
||||||
github.com/golang/protobuf v1.5.3 // indirect
|
github.com/golang/protobuf v1.5.3 // indirect
|
||||||
github.com/golang/snappy v0.0.4 // indirect
|
github.com/golang/snappy v0.0.4 // indirect
|
||||||
|
2
go.sum
2
go.sum
@ -299,6 +299,8 @@ github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk=
|
|||||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||||
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
|
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
|
||||||
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls=
|
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls=
|
||||||
|
github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
|
||||||
|
github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
|
||||||
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||||
github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw=
|
github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw=
|
||||||
github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
|
github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
|
||||||
|
@ -29,7 +29,7 @@ type ShareRequest struct {
|
|||||||
Frontends []string
|
Frontends []string
|
||||||
BasicAuth []string
|
BasicAuth []string
|
||||||
OauthProvider string
|
OauthProvider string
|
||||||
OauthEmailDomains []string
|
OauthEmailAddressPatterns []string
|
||||||
OauthAuthorizationCheckInterval time.Duration
|
OauthAuthorizationCheckInterval time.Duration
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -84,7 +84,7 @@ func newPublicShare(root env_core.Root, request *ShareRequest) *share.ShareParam
|
|||||||
BackendMode: string(request.BackendMode),
|
BackendMode: string(request.BackendMode),
|
||||||
BackendProxyEndpoint: request.Target,
|
BackendProxyEndpoint: request.Target,
|
||||||
AuthScheme: string(None),
|
AuthScheme: string(None),
|
||||||
OauthEmailDomains: request.OauthEmailDomains,
|
OauthEmailDomains: request.OauthEmailAddressPatterns,
|
||||||
OauthProvider: request.OauthProvider,
|
OauthProvider: request.OauthProvider,
|
||||||
OauthAuthorizationCheckInterval: request.OauthAuthorizationCheckInterval.String(),
|
OauthAuthorizationCheckInterval: request.OauthAuthorizationCheckInterval.String(),
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,7 @@ class ShareRequest:
|
|||||||
Frontends: list[str] = field(default_factory=list[str])
|
Frontends: list[str] = field(default_factory=list[str])
|
||||||
BasicAuth: list[str] = field(default_factory=list[str])
|
BasicAuth: list[str] = field(default_factory=list[str])
|
||||||
OauthProvider: str = ""
|
OauthProvider: str = ""
|
||||||
OauthEmailDomains: list[str] = field(default_factory=list[str])
|
OauthEmailAddressPatterns: list[str] = field(default_factory=list[str])
|
||||||
OauthAuthorizationCheckInterval: str = ""
|
OauthAuthorizationCheckInterval: str = ""
|
||||||
Reserved: bool = False
|
Reserved: bool = False
|
||||||
UniqueName: str = ""
|
UniqueName: str = ""
|
||||||
|
@ -78,7 +78,7 @@ def __newPublicShare(root: Root, request: model.ShareRequest) -> ShareRequest:
|
|||||||
backend_mode=request.BackendMode,
|
backend_mode=request.BackendMode,
|
||||||
backend_proxy_endpoint=request.Target,
|
backend_proxy_endpoint=request.Target,
|
||||||
auth_scheme=model.AUTH_SCHEME_NONE,
|
auth_scheme=model.AUTH_SCHEME_NONE,
|
||||||
oauth_email_domains=request.OauthEmailDomains,
|
oauth_email_domains=request.OauthEmailAddressPatterns,
|
||||||
oauth_authorization_check_interval=request.OauthAuthorizationCheckInterval
|
oauth_authorization_check_interval=request.OauthAuthorizationCheckInterval
|
||||||
)
|
)
|
||||||
if request.OauthProvider != "":
|
if request.OauthProvider != "":
|
||||||
|
Loading…
Reference in New Issue
Block a user