Skip to content

Commit

Permalink
Initial implementation of keycloak IDP lookups. Does not yet create n…
Browse files Browse the repository at this point in the history
…ew users
  • Loading branch information
evankanderson committed Apr 24, 2024
1 parent dbb5831 commit c177b79
Show file tree
Hide file tree
Showing 20 changed files with 17,136 additions and 21 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/license-check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,5 @@ jobs:
- name: Check license headers
run: |
set -e
addlicense -l apache -c 'Stacklok, Inc' -v -ignore "pkg/generated/*" -ignore "**/database/query/**" -ignore "internal/db/*" -ignore "docs/docs/**" -ignore "docs/src/**" -ignore "docs/static/**" -ignore "pkg/controlplane/policy_types/**" -ignore "docs/build/**" -ignore "examples/**" *
addlicense -l apache -c 'Stacklok, Inc' -v -ignore "pkg/generated/*" -ignore "**/database/query/**" -ignore "internal/db/*" -ignore "docs/docs/**" -ignore "docs/src/**" -ignore "docs/static/**" -ignore "pkg/controlplane/policy_types/**" -ignore "docs/build/**" -ignore "examples/**" -ignore "internal/auth/keycloak/client/keycloak-api.yaml" *
git diff --exit-code
6 changes: 5 additions & 1 deletion .mk/gen.mk
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ clean-gen: ## clean generated files
rm -rf $(shell find pkg/api -iname "*.go") & rm -rf $(shell find pkg/api -iname "*.swagger.json") & rm -rf pkg/api/protodocs

.PHONY: gen
gen: buf sqlc mock ## run code generation targets (buf, sqlc, mock)
gen: buf sqlc mock oapi ## run code generation targets (buf, sqlc, mock)
$(MAKE) authz-model

.PHONY: buf
Expand All @@ -29,6 +29,10 @@ buf: ## generate protobuf files
sqlc: ## generate sqlc files
sqlc generate

.PHONY: oapi
oapi: ## generate openapi files
go generate ./internal/auth/keycloak/client

.PHONY: mock
mock: ## generate mocks
mockgen -package mockdb -destination database/mock/store.go github.com/stacklok/minder/internal/db Store
Expand Down
2 changes: 1 addition & 1 deletion .mk/test.mk
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
# exclude auto-generated DB code as well as mocks
# in future, we may want to parse these from a file instead of hardcoding them
# in the Makefile
COVERAGE_EXCLUSIONS="internal/db\|/mock/"
COVERAGE_EXCLUSIONS="internal/db\|/mock/|internal/auth/keycloak/client"
COVERAGE_PACKAGES=./internal/...

.PHONY: clean
Expand Down
11 changes: 11 additions & 0 deletions cmd/server/app/serve.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import (
"github.com/spf13/viper"

"github.com/stacklok/minder/internal/auth"
"github.com/stacklok/minder/internal/auth/keycloak"
"github.com/stacklok/minder/internal/authz"
"github.com/stacklok/minder/internal/config"
serverconfig "github.com/stacklok/minder/internal/config/server"
Expand Down Expand Up @@ -103,6 +104,15 @@ var serveCmd = &cobra.Command{
return fmt.Errorf("unable to prepare authz client for run: %w", err)
}

kc, err := keycloak.NewKeyCloak("", cfg.Identity.Server)
if err != nil {
return fmt.Errorf("unable to create keycloak identity provider: %w", err)
}
idClient, err := auth.NewIdentityClient(kc)
if err != nil {
return fmt.Errorf("unable to create identity client: %w", err)
}

providerMetrics := provtelemetry.NewProviderMetrics()
restClientCache := ratecache.NewRestClientCache(ctx)
defer restClientCache.Close()
Expand All @@ -111,6 +121,7 @@ var serveCmd = &cobra.Command{
controlplane.WithServerMetrics(cpmetrics.NewMetrics()),
controlplane.WithProviderMetrics(providerMetrics),
controlplane.WithAuthzClient(authzc),
controlplane.WithIdentityClient(idClient),
controlplane.WithRestClientCache(restClientCache),
}

Expand Down
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ require (
github.com/lib/pq v1.10.9
github.com/mitchellh/mapstructure v1.5.0
github.com/motemen/go-loghttp v0.0.0-20231107055348-29ae44b293f4
github.com/oapi-codegen/runtime v1.1.1
github.com/olekukonko/tablewriter v0.0.5
github.com/open-policy-agent/opa v0.63.0
github.com/openfga/go-sdk v0.3.5
Expand Down Expand Up @@ -84,6 +85,7 @@ require (
github.com/MicahParks/keyfunc v1.9.0 // indirect
github.com/Microsoft/hcsshim v0.11.4 // indirect
github.com/antlr4-go/antlr/v4 v4.13.0 // indirect
github.com/apapsch/go-jsonmerge/v2 v2.0.0 // indirect
github.com/atotto/clipboard v0.1.4 // indirect
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
github.com/charmbracelet/bubbles v0.17.1 // indirect
Expand Down
8 changes: 8 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ github.com/OneOfOne/xxhash v1.2.8 h1:31czK/TI9sNkxIKfaUfGlU47BAxQ0ztGgd9vPyqimf8
github.com/OneOfOne/xxhash v1.2.8/go.mod h1:eZbhyaAYD41SGSSsnmcpxVoRiQ/MPUTjUdIIOT9Um7Q=
github.com/ProtonMail/go-crypto v1.0.0 h1:LRuvITjQWX+WIfr930YHG2HNfjR1uOfyf5vE0kC2U78=
github.com/ProtonMail/go-crypto v1.0.0/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0=
github.com/RaveNoX/go-jsoncommentstrip v1.0.0/go.mod h1:78ihd09MekBnJnxpICcwzCMzGrKSKYe4AqU6PDYYpjk=
github.com/ThreeDotsLabs/watermill v1.1.1/go.mod h1:Qd1xNFxolCAHCzcMrm6RnjW0manbvN+DJVWc1MWRFlI=
github.com/ThreeDotsLabs/watermill v1.3.5 h1:50JEPEhMGZQMh08ct0tfO1PsgMOAOhV3zxK2WofkbXg=
github.com/ThreeDotsLabs/watermill v1.3.5/go.mod h1:O/u/Ptyrk5MPTxSeWM5vzTtZcZfxXfO9PK9eXTYiFZY=
Expand All @@ -109,6 +110,8 @@ github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230512164433-5d1fd1a340c9 h
github.com/antlr/antlr4/runtime/Go/antlr/v4 v4.0.0-20230512164433-5d1fd1a340c9/go.mod h1:pSwJ0fSY5KhvocuWSx4fz3BA8OrA1bQn+K1Eli3BRwM=
github.com/antlr4-go/antlr/v4 v4.13.0 h1:lxCg3LAv+EUK6t1i0y1V6/SLeUi0eKEKdhQAlS8TVTI=
github.com/antlr4-go/antlr/v4 v4.13.0/go.mod h1:pfChB/xh/Unjila75QW7+VU4TSnWnnk9UTnmpPaOR2g=
github.com/apapsch/go-jsonmerge/v2 v2.0.0 h1:axGnT1gRIfimI7gJifB699GoE/oq+F2MU7Dml6nw9rQ=
github.com/apapsch/go-jsonmerge/v2 v2.0.0/go.mod h1:lvDnEdqiQrp0O42VQGgmlKpxL1AP2+08jFMw88y4klk=
github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0 h1:jfIu9sQUG6Ig+0+Ap1h4unLjW6YQJpKZVmUzxsD4E/Q=
github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0/go.mod h1:t2tdKJDJF9BV14lnkjHmOQgcvEKgtqs5a1N3LNdJhGE=
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
Expand Down Expand Up @@ -158,6 +161,7 @@ github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/blang/semver v3.5.1+incompatible h1:cQNTCjp13qL8KC3Nbxr/y2Bqb63oX6wdnnjpJbkM4JQ=
github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
github.com/bmatcuk/doublestar v1.1.1/go.mod h1:UD6OnuiIn0yFxxA2le/rnRU1G4RaI4UvFv1sNto9p6w=
github.com/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0=
github.com/bytecodealliance/wasmtime-go/v3 v3.0.2 h1:3uZCA/BLTIu+DqCfguByNMJa2HVHpXvjfy0Dy7g6fuA=
github.com/bytecodealliance/wasmtime-go/v3 v3.0.2/go.mod h1:RnUjnIXxEJcL6BgCvNyzCCRzZcxCgsZCi+RNlvYor5Q=
Expand Down Expand Up @@ -569,6 +573,7 @@ github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFF
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
github.com/juju/gnuflag v0.0.0-20171113085948-2ce1bb71843d/go.mod h1:2PavIy+JPciBPrBUjwbNvtwB6RQlve+hkpll6QSNmOE=
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/karlseguin/ccache/v3 v3.0.5 h1:hFX25+fxzNjsRlREYsoGNa2LoVEw5mPF8wkWq/UnevQ=
github.com/karlseguin/ccache/v3 v3.0.5/go.mod h1:qxC372+Qn+IBj8Pe3KvGjHPj0sWwEF7AeZVhsNPZ6uY=
Expand Down Expand Up @@ -690,6 +695,8 @@ github.com/natefinch/wrap v0.2.0 h1:IXzc/pw5KqxJv55gV0lSOcKHYuEZPGbQrOOXr/bamRk=
github.com/natefinch/wrap v0.2.0/go.mod h1:6gMHlAl12DwYEfKP3TkuykYUfLSEAvHw67itm4/KAS8=
github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4=
github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls=
github.com/oapi-codegen/runtime v1.1.1 h1:EXLHh0DXIJnWhdRPN2w4MXAzFyE4CskzhNLUmtpMYro=
github.com/oapi-codegen/runtime v1.1.1/go.mod h1:SK9X900oXmPWilYR5/WKPzt3Kqxn/uS/+lbpREv+eCg=
github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4=
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
github.com/oklog/ulid/v2 v2.1.0 h1:+9lhoxAP56we25tyYETBBY1YLA2SaoLvUFgrP2miPJU=
Expand Down Expand Up @@ -857,6 +864,7 @@ github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/viper v1.18.2 h1:LUXCnvUvSM6FXAsj6nnfc8Q2tp1dIgUfY9Kc8GsSOiQ=
github.com/spf13/viper v1.18.2/go.mod h1:EKmWIqdnk5lOcmR72yw6hS+8OPYcwD0jteitLMVB+yk=
github.com/spkg/bom v0.0.0-20160624110644-59b7046e48ad/go.mod h1:qLr4V1qq6nMqFKkMo8ZTx3f+BZEkzsRUY10Xsm2mwU0=
github.com/sqlc-dev/pqtype v0.3.0 h1:b09TewZ3cSnO5+M1Kqq05y0+OjqIptxELaSayg7bmqk=
github.com/sqlc-dev/pqtype v0.3.0/go.mod h1:oyUjp5981ctiL9UYvj1bVvCKi8OXkCa0u645hce7CAs=
github.com/stacklok/frizbee v0.0.15 h1:W3gocAzapIvQAm1MTF5GFBwGQSCdv0Kk/CweTNGb5IY=
Expand Down
19 changes: 11 additions & 8 deletions internal/auth/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ func (i *Identity) Human() string {
p := i.Provider.String()
if p == "" {
// Special case for provider registered as "".
return i.UserID
return i.HumanName
}
return fmt.Sprintf("%s/%s", i.HumanName, p)
}
Expand Down Expand Up @@ -114,24 +114,26 @@ type IdentityProvider interface {
// IdentityClient supports the ability to look up identities in one or more
// IdentityProviders.
type IdentityClient struct {
// This map is a bit overloaded; it maps both short provider names
providers xsync.MapOf[string, IdentityProvider] // map[string]IdentityProvider
// This map is a bit overloaded; it maps both short provider names and URLs to IdentityProviders.
providers *xsync.MapOf[string, IdentityProvider] // map[string]IdentityProvider
}

var _ Resolver = (*IdentityClient)(nil)

// NewIdentityClient creates a new IdentityClient with the supplied providers.
func NewIdentityClient(providers ...IdentityProvider) (*IdentityClient, error) {
c := &IdentityClient{
providers: xsync.NewMapOfPresized(len(providers) * 2),
providers: xsync.NewMapOfPresized[string, IdentityProvider](len(providers) * 2),
}
for _, p := range providers {
u := p.URL() // URL's String has a pointer receiver

prev, ok := c.providers.LoadOrStore(p.String(), p)
if ok { // We had an existing value, this is a configuration error.
return nil, fmt.Errorf("duplicate provider for %q, new %s, old %s", p.String(), p.URL(), prev.URL())
prevUrl := prev.URL()
return nil, fmt.Errorf("duplicate provider for %q, new %s, old %s", p.String(), u.String(), prevUrl.String())
}

u := p.URL() // URL's String has a pointer receiver
prev, ok = c.providers.LoadOrStore(u.String(), p)
if ok { // We had an existing value, this is a configuration error.
return nil, fmt.Errorf("duplicate provider for URL %s, new %q, old %q", u.String(), p.String(), prev.String())
Expand All @@ -145,13 +147,14 @@ func (c *IdentityClient) Register(p IdentityProvider) error {
if c == nil {
return errors.New("cannot register with a nil IdentityClient")
}
u := p.URL() // URL's String has a pointer receiver

prev, ok := c.providers.LoadOrStore(p.String(), p)
if ok { // We had an existing value, this is a configuration error.
return fmt.Errorf("duplicate provider for %q, new %s, old %s", p.String(), p.URL(), prev.URL())
prevUrl := prev.URL()
return fmt.Errorf("duplicate provider for %q, new %s, old %s", p.String(), u.String(), prevUrl.String())
}

u := p.URL() // URL's String has a pointer receiver
prev, ok = c.providers.LoadOrStore(u.String(), p)
if ok { // We had an existing value, this is a configuration error.
return fmt.Errorf("duplicate provider for URL %s, new %q, old %q", u.String(), p.String(), prev.String())
Expand Down
Loading

0 comments on commit c177b79

Please sign in to comment.