Skip to content

Commit

Permalink
more cleanup
Browse files Browse the repository at this point in the history
  • Loading branch information
dcarbone committed Sep 2, 2020
1 parent 851c24d commit 91b96f0
Show file tree
Hide file tree
Showing 2 changed files with 77 additions and 65 deletions.
57 changes: 30 additions & 27 deletions api_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -535,6 +535,8 @@ func (e *RealmEnvConfig) PolicyEndpoint() (string, bool) {
return "", false
}

// RealmAPIClient is intended for use against a singular realm within your Keycloak instance. All internal calls will
// be scoped to the provided realm
type RealmAPIClient struct {
*APIClient
log zerolog.Logger
Expand Down Expand Up @@ -566,32 +568,6 @@ func (c *APIClient) RealmAPIClient(ctx context.Context, realmName string, mutato
return rc, nil
}

func (c *APIClient) TokenAPIClient(ctx context.Context, realmName string, tp TokenProvider, mutators ...RequestMutator) (*TokenAPIClient, error) {
var (
rc *RealmAPIClient
err error
)
if rc, err = c.RealmAPIClient(ctx, realmName, mutators...); err != nil {
return nil, err
}
return rc.TokenClient(tp)
}

func (c *APIClient) TokenAPIClientFromProvider(ctx context.Context, tp FixedRealmTokenProvider, mutators ...RequestMutator) (*TokenAPIClient, error) {
return c.TokenAPIClient(ctx, tp.TargetRealm(), tp, mutators...)
}

func (c *APIClient) TokenAPIClientForConfidentialClient(ctx context.Context, tpc *ConfidentialClientTokenProviderConfig, mutators ...RequestMutator) (*TokenAPIClient, error) {
var (
tp *ConfidentialClientTokenProvider
err error
)
if tp, err = NewConfidentialClientTokenProvider(tpc); err != nil {
return nil, fmt.Errorf("error constructing confidential client token provider: %w", err)
}
return c.TokenAPIClientFromProvider(ctx, tp, mutators...)
}

// RealmName returns the realm this client instance is scoped to
func (rc *RealmAPIClient) RealmName() string {
return rc.rn
Expand Down Expand Up @@ -790,7 +766,8 @@ func (rc *RealmAPIClient) keyFunc(ctx context.Context) jwt.Keyfunc {

// TokenAPIClient
//
// This is an extension of the RealmAPIClient that is further scoped by a single TokenProvider
// This is an extension of the RealmAPIClient that is further scoped by a single TokenProvider, where all requests will
// have the provided token sent in the Authorization header.
type TokenAPIClient struct {
*RealmAPIClient
tp TokenProvider
Expand All @@ -805,6 +782,32 @@ func (rc *RealmAPIClient) TokenClient(tp TokenProvider) (*TokenAPIClient, error)
return tc, nil
}

func (c *APIClient) TokenAPIClient(ctx context.Context, realmName string, tp TokenProvider, mutators ...RequestMutator) (*TokenAPIClient, error) {
var (
rc *RealmAPIClient
err error
)
if rc, err = c.RealmAPIClient(ctx, realmName, mutators...); err != nil {
return nil, err
}
return rc.TokenClient(tp)
}

func (c *APIClient) TokenAPIClientFromProvider(ctx context.Context, tp FixedRealmTokenProvider, mutators ...RequestMutator) (*TokenAPIClient, error) {
return c.TokenAPIClient(ctx, tp.TargetRealm(), tp, mutators...)
}

func (c *APIClient) TokenAPIClientForConfidentialClient(ctx context.Context, tpc *ConfidentialClientTokenProviderConfig, mutators ...RequestMutator) (*TokenAPIClient, error) {
var (
tp *ConfidentialClientTokenProvider
err error
)
if tp, err = NewConfidentialClientTokenProvider(tpc); err != nil {
return nil, fmt.Errorf("error constructing confidential client token provider: %w", err)
}
return c.TokenAPIClientFromProvider(ctx, tp, mutators...)
}

func (tc *TokenAPIClient) TokenProvider() TokenProvider {
return tc.tp
}
Expand Down
85 changes: 47 additions & 38 deletions api_client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,53 +28,79 @@ func usableClientID(t *testing.T) string {
return cid
}

type staticTP string
type staticTP struct {
token string
realm string
}

func (tp staticTP) TargetRealm() string {
return tp.realm
}

func (tp staticTP) BearerToken() (string, error) {
return string(tp), nil
return tp.token, nil
}

func newStaticTP(token, realm string) staticTP {
return staticTP{token, realm}
}

func newClient(t *testing.T, mutators ...keycloak.ConfigMutator) *keycloak.TokenAPIClient {
t.Helper()
var (
ip keycloak.IssuerProvider
tp keycloak.TokenProvider
tp keycloak.FixedRealmTokenProvider
err error

issAddr = os.Getenv(EnvIssuerAddr)
kcRealm = os.Getenv(EnvKeycloakRealm)
bt = os.Getenv(EnvBearerToken)
issAddr = os.Getenv(EnvIssuerAddr)
kcRealm = os.Getenv(EnvKeycloakRealm)
bearerToken = os.Getenv(EnvBearerToken)
)

if issAddr != "" {
ip = keycloak.NewStaticIssuerProvider(issAddr)
}

if bt != "" {
stp := new(staticTP)
*stp = staticTP(bt)
tp = stp
t.Logf("Using test-only StaticTokenProvider with token: %s", bt)
if bearerToken != "" {
tp = newStaticTP(bearerToken, kcRealm)
t.Logf("Using test-only StaticTokenProvider with token: %s", bearerToken)
}

conf := keycloak.DefaultAPIClientConfig([]keycloak.TokenParser{keycloak.NewX509TokenParser(keycloak.NewPublicKeyCache())})
conf.IssuerProvider = ip
if mutators == nil {
mutators = make([]keycloak.ConfigMutator, 0)
}
mutators = append(
mutators,
func(config *keycloak.APIClientConfig) {
config.IssuerProvider = ip
},
)

cl, err := keycloak.NewAPIClient(nil, mutators...)
if err != nil {
t.Logf("Error creating api client: %s", err)
t.FailNow()
return nil
}

cl, err := keycloak.NewAPIClient(conf, mutators...)
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
tcl, err := cl.TokenAPIClientFromProvider(ctx, tp)
if err != nil {
t.Logf("Error creating client: %s", err)
t.Logf("Error creating token api client: %v", err)
t.FailNow()
return nil
}
return cl

return tcl
}

func TestRealmIssuerConfig(t *testing.T) {
t.Parallel()
cl := newClient(t)
ks := cl.AuthService()
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
defer cancel()
config, err := ks.RealmIssuerConfiguration(ctx)
config, err := cl.RealmIssuerConfiguration(ctx)
if err != nil {
t.Logf("Error fetching Realm Issuer Configuration: %s", err)
t.Fail()
Expand All @@ -87,10 +113,9 @@ func TestWellKnownConfigs(t *testing.T) {
t.Run("oidc", func(t *testing.T) {
t.Parallel()
cl := newClient(t)
ks := cl.AuthService()
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
defer cancel()
oidc, err := ks.OpenIDConfiguration(ctx)
oidc, err := cl.OpenIDConfiguration(ctx)
if err != nil {
t.Logf("Error fetching OIDC: %s", err)
t.Fail()
Expand All @@ -101,10 +126,9 @@ func TestWellKnownConfigs(t *testing.T) {
t.Run("uma2", func(t *testing.T) {
t.Parallel()
cl := newClient(t)
ks := cl.AuthService()
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
defer cancel()
uma2, err := ks.UMA2Configuration(ctx)
uma2, err := cl.UMA2Configuration(ctx)
if err != nil {
if keycloak.IsAPIError(err) && err.(*keycloak.APIError).ResponseCode != http.StatusNotFound {
t.Logf("Error fetching UMA2 config: %s", err)
Expand All @@ -121,27 +145,12 @@ func TestRPT(t *testing.T) {
t.Parallel()
cl := newClient(t)
cid := usableClientID(t)
ks := cl.AuthService()
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
defer cancel()

ctx, err := cl.RequireToken(ctx)
if err != nil {
t.Logf("Error requiring token: %v", err)
t.FailNow()
return
}

_, ok := keycloak.ContextToken(ctx)
if !ok {
t.Log("Token missing from context")
t.FailNow()
return
}

req := keycloak.NewOpenIDConnectTokenRequest(keycloak.GrantTypeUMA2Ticket)
req.Audience = cid
_, err = ks.OpenIDConnectToken(ctx, req)
_, err := cl.OpenIDConnectToken(ctx, req)
if err != nil {
t.Logf("Error fetching RPT: %s", err)
t.Fail()
Expand Down

0 comments on commit 91b96f0

Please sign in to comment.