Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CloundFoundry connector #1624

Open
wants to merge 15 commits into
base: master
Choose a base branch
from
4 changes: 2 additions & 2 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -121,8 +121,8 @@ jobs:
DEX_ETCD_ENDPOINTS: http://localhost:${{ job.services.etcd.ports[2379] }}

DEX_LDAP_HOST: localhost
DEX_LDAP_PORT: 389
DEX_LDAP_TLS_PORT: 636
DEX_LDAP_PORT: 3890
DEX_LDAP_TLS_PORT: 6360

DEX_KEYSTONE_URL: http://localhost:${{ job.services.keystone.ports[5000] }}
DEX_KEYSTONE_ADMIN_URL: http://localhost:${{ job.services.keystone.ports[35357] }}
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ Dex implements the following connectors:
| [Atlassian Crowd](https://dexidp.io/docs/connectors/atlassiancrowd/) | yes | yes | yes * | beta | preferred_username claim must be configured through config |
| [Gitea](https://dexidp.io/docs/connectors/gitea/) | yes | no | yes | beta | |
| [OpenStack Keystone](https://dexidp.io/docs/connectors/keystone/) | yes | yes | no | alpha | |
| [Cloud Foundry](https://dexidp.io/docs/connectors/cloudfoundry/) | no | yes | no | alpha | This connector is community maintained by [Concourse](https://github.com/concourse) |

Stable, beta, and alpha are defined as:

Expand Down
46 changes: 27 additions & 19 deletions cmd/docker-entrypoint/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,20 +22,13 @@ func main() {
os.Exit(1)
}

if err := run(args, realExec, realWhich); err != nil {
if err := run(args, realExec, realWhich, realGomplate); err != nil {
fmt.Println("error:", err.Error())
os.Exit(1)
}
}

func realExec(fork bool, args ...string) error {
if fork {
if output, err := exec.Command(args[0], args[1:]...).CombinedOutput(); err != nil {
return fmt.Errorf("cannot fork/exec command %s: %w (output: %q)", args, err, string(output))
}
return nil
}

func realExec(args ...string) error {
argv0, err := exec.LookPath(args[0])
if err != nil {
return fmt.Errorf("cannot lookup path for command %s: %w", args[0], err)
Expand All @@ -56,34 +49,49 @@ func realWhich(path string) string {
return fullPath
}

func run(args []string, execFunc func(bool, ...string) error, whichFunc func(string) string) error {
func realGomplate(path string) (string, error) {
tmpFile, err := os.CreateTemp("/tmp", "dex.config.yaml-*")
if err != nil {
return "", fmt.Errorf("cannot create temp file: %w", err)
}

cmd := exec.Command("gomplate", "-f", path, "-o", tmpFile.Name())
// TODO(nabokihms): Workaround to run gomplate from a non-root directory in distroless images
// gomplate tries to access CWD on start, see: https://github.com/hairyhenderson/gomplate/pull/2202
cmd.Dir = "/etc/dex"

output, err := cmd.CombinedOutput()
if err != nil {
return "", fmt.Errorf("error executing gomplate: %w, (output: %q)", err, string(output))
}

return tmpFile.Name(), nil
}

func run(args []string, execFunc func(...string) error, whichFunc func(string) string, gomplateFunc func(string) (string, error)) error {
if args[0] != "dex" && args[0] != whichFunc("dex") {
return execFunc(false, args...)
return execFunc(args...)
}

if args[1] != "serve" {
return execFunc(false, args...)
return execFunc(args...)
}

newArgs := []string{}
for _, tplCandidate := range args {
if hasSuffixes(tplCandidate, ".tpl", ".tmpl", ".yaml") {
tmpFile, err := os.CreateTemp("/tmp", "dex.config.yaml-*")
fileName, err := gomplateFunc(tplCandidate)
if err != nil {
return fmt.Errorf("cannot create temp file: %w", err)
}

if err := execFunc(true, "gomplate", "-f", tplCandidate, "-o", tmpFile.Name()); err != nil {
return err
}

newArgs = append(newArgs, tmpFile.Name())
newArgs = append(newArgs, fileName)
} else {
newArgs = append(newArgs, tplCandidate)
}
}

return execFunc(false, newArgs...)
return execFunc(newArgs...)
}

func hasSuffixes(s string, suffixes ...string) bool {
Expand Down
79 changes: 35 additions & 44 deletions cmd/docker-entrypoint/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import (
)

type execArgs struct {
fork bool
gomplate bool
argPrefixes []string
}

Expand All @@ -16,98 +16,89 @@ func TestRun(t *testing.T) {
args []string
execReturns error
whichReturns string
wantExecArgs []execArgs
wantExecArgs execArgs
wantErr error
}{
{
name: "executable not dex",
args: []string{"tuna", "fish"},
wantExecArgs: []execArgs{{fork: false, argPrefixes: []string{"tuna", "fish"}}},
wantExecArgs: execArgs{gomplate: false, argPrefixes: []string{"tuna", "fish"}},
},
{
name: "executable is full path to dex",
args: []string{"/usr/local/bin/dex", "marshmallow", "zelda"},
whichReturns: "/usr/local/bin/dex",
wantExecArgs: []execArgs{{fork: false, argPrefixes: []string{"/usr/local/bin/dex", "marshmallow", "zelda"}}},
wantExecArgs: execArgs{gomplate: false, argPrefixes: []string{"/usr/local/bin/dex", "marshmallow", "zelda"}},
},
{
name: "command is not serve",
args: []string{"dex", "marshmallow", "zelda"},
wantExecArgs: []execArgs{{fork: false, argPrefixes: []string{"dex", "marshmallow", "zelda"}}},
wantExecArgs: execArgs{gomplate: false, argPrefixes: []string{"dex", "marshmallow", "zelda"}},
},
{
name: "no templates",
args: []string{"dex", "serve", "config.yaml.not-a-template"},
wantExecArgs: []execArgs{{fork: false, argPrefixes: []string{"dex", "serve", "config.yaml.not-a-template"}}},
wantExecArgs: execArgs{gomplate: false, argPrefixes: []string{"dex", "serve", "config.yaml.not-a-template"}},
},
{
name: "no templates",
args: []string{"dex", "serve", "config.yaml.not-a-template"},
wantExecArgs: []execArgs{{fork: false, argPrefixes: []string{"dex", "serve", "config.yaml.not-a-template"}}},
wantExecArgs: execArgs{gomplate: false, argPrefixes: []string{"dex", "serve", "config.yaml.not-a-template"}},
},
{
name: ".tpl template",
args: []string{"dex", "serve", "config.tpl"},
wantExecArgs: []execArgs{
{fork: true, argPrefixes: []string{"gomplate", "-f", "config.tpl", "-o", "/tmp/dex.config.yaml-"}},
{fork: false, argPrefixes: []string{"dex", "serve", "/tmp/dex.config.yaml-"}},
},
name: ".tpl template",
args: []string{"dex", "serve", "config.tpl"},
wantExecArgs: execArgs{gomplate: true, argPrefixes: []string{"dex", "serve", "/tmp/dex.config.yaml-"}},
},
{
name: ".tmpl template",
args: []string{"dex", "serve", "config.tmpl"},
wantExecArgs: []execArgs{
{fork: true, argPrefixes: []string{"gomplate", "-f", "config.tmpl", "-o", "/tmp/dex.config.yaml-"}},
{fork: false, argPrefixes: []string{"dex", "serve", "/tmp/dex.config.yaml-"}},
},
name: ".tmpl template",
args: []string{"dex", "serve", "config.tmpl"},
wantExecArgs: execArgs{gomplate: true, argPrefixes: []string{"dex", "serve", "/tmp/dex.config.yaml-"}},
},
{
name: ".yaml template",
args: []string{"dex", "serve", "some/path/config.yaml"},
wantExecArgs: []execArgs{
{fork: true, argPrefixes: []string{"gomplate", "-f", "some/path/config.yaml", "-o", "/tmp/dex.config.yaml-"}},
{fork: false, argPrefixes: []string{"dex", "serve", "/tmp/dex.config.yaml-"}},
},
name: ".yaml template",
args: []string{"dex", "serve", "some/path/config.yaml"},
wantExecArgs: execArgs{gomplate: true, argPrefixes: []string{"dex", "serve", "/tmp/dex.config.yaml-"}},
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
var gotExecForks []bool
var gotExecArgs [][]string
fakeExec := func(fork bool, args ...string) error {
gotExecForks = append(gotExecForks, fork)
gotExecArgs = append(gotExecArgs, args)
var gotExecArgs []string
var runsGomplate bool

fakeExec := func(args ...string) error {
gotExecArgs = append(args, gotExecArgs...)
return test.execReturns
}

fakeWhich := func(_ string) string { return test.whichReturns }

gotErr := run(test.args, fakeExec, fakeWhich)
fakeGomplate := func(file string) (string, error) {
runsGomplate = true
return "/tmp/dex.config.yaml-", nil
}

gotErr := run(test.args, fakeExec, fakeWhich, fakeGomplate)
if (test.wantErr == nil) != (gotErr == nil) {
t.Errorf("wanted error %s, got %s", test.wantErr, gotErr)
}
if !execArgsMatch(test.wantExecArgs, gotExecForks, gotExecArgs) {
t.Errorf("wanted exec args %+v, got %+v %+v", test.wantExecArgs, gotExecForks, gotExecArgs)

if !execArgsMatch(test.wantExecArgs, runsGomplate, gotExecArgs) {
t.Errorf("wanted exec args %+v (running gomplate: %+v), got %+v (running gomplate: %+v)",
test.wantExecArgs.argPrefixes, test.wantExecArgs.gomplate, gotExecArgs, runsGomplate)
}
})
}
}

func execArgsMatch(wantExecArgs []execArgs, gotForks []bool, gotExecArgs [][]string) bool {
if len(wantExecArgs) != len(gotForks) {
func execArgsMatch(wantExecArgs execArgs, gomplate bool, gotExecArgs []string) bool {
if wantExecArgs.gomplate != gomplate {
return false
}

for i := range wantExecArgs {
if wantExecArgs[i].fork != gotForks[i] {
for i := range wantExecArgs.argPrefixes {
if !strings.HasPrefix(gotExecArgs[i], wantExecArgs.argPrefixes[i]) {
return false
}
for j := range wantExecArgs[i].argPrefixes {
if !strings.HasPrefix(gotExecArgs[i][j], wantExecArgs[i].argPrefixes[j]) {
return false
}
}
}

return true
}
Loading
Loading