Browse Source

Access token provided for each request

master
harture 7 years ago
parent
commit
93716aa74d
  1. 122
      Gopkg.lock
  2. 3
      README.md
  3. 12
      attack_detection.go
  4. 116
      authentication_management.go
  5. 24
      client_attribute_certificate.go
  6. 12
      client_initial_access.go
  7. 4
      client_registration_policy.go
  8. 12
      client_role_mappings.go
  9. 1
      client_templates.go
  10. 12
      clients.go
  11. 53
      clients_test.go
  12. 1
      component.go
  13. 1
      groups.go
  14. 1
      identity_providers.go
  15. BIN
      integration/integration
  16. 60
      integration/integration.go
  17. 1
      key.go
  18. 123
      keycloak_client.go
  19. 40
      keycloak_client_test.go
  20. 24
      realm.go
  21. 25
      realm_test.go
  22. 1
      realms_admin.go
  23. 1
      role_mapper.go
  24. 1
      roles.go
  25. 1
      root.go
  26. 1
      scope_mappings.go
  27. 1
      user_storage_provider.go
  28. 24
      users.go
  29. 23
      users_test.go

122
Gopkg.lock

@ -3,97 +3,199 @@
[[projects]]
branch = "v2"
digest = "1:e193a6789a00fd6fee10f8e5d070eb3f1dcf19d7fdaff61f23ffdcd42dae7d9e"
name = "github.com/coreos/go-oidc"
packages = ["."]
pruneopts = ""
revision = "065b426bd41667456c1a924468f507673629c46b"
[[projects]]
digest = "1:56c130d885a4aacae1dd9c7b71cfe39912c7ebc1ff7d2b46083c8812996dc43b"
name = "github.com/davecgh/go-spew"
packages = ["spew"]
pruneopts = ""
revision = "346938d642f2ec3594ed81d874461961cd0faa76"
version = "v1.1.0"
[[projects]]
digest = "1:bcb38c8fc9b21bb8682ce2d605a7d4aeb618abc7f827e3ac0b27c0371fdb23fb"
name = "github.com/golang/protobuf"
packages = ["proto"]
pruneopts = ""
revision = "925541529c1fa6821df4e44ce2723319eb2be768"
version = "v1.0.0"
[[projects]]
digest = "1:7365acd48986e205ccb8652cc746f09c8b7876030d53710ea6ef7d0bd0dcd7ca"
name = "github.com/pkg/errors"
packages = ["."]
pruneopts = ""
revision = "645ef00459ed84a119197bfb8d8205042c6df63d"
version = "v0.8.0"
[[projects]]
digest = "1:256484dbbcd271f9ecebc6795b2df8cad4c458dd0f5fd82a8c2fa0c29f233411"
name = "github.com/pmezard/go-difflib"
packages = ["difflib"]
pruneopts = ""
revision = "792786c7400a136282c1664665ae0a8db921c6c2"
version = "v1.0.0"
[[projects]]
branch = "master"
digest = "1:386e12afcfd8964907c92dffd106860c0dedd71dbefae14397b77b724a13343b"
name = "github.com/pquerna/cachecontrol"
packages = [".","cacheobject"]
packages = [
".",
"cacheobject",
]
pruneopts = ""
revision = "0dec1b30a0215bb68605dfc568e8855066c9202d"
[[projects]]
digest = "1:261bc565833ef4f02121450d74eb88d5ae4bd74bfe5d0e862cddb8550ec35000"
name = "github.com/spf13/pflag"
packages = ["."]
pruneopts = ""
revision = "e57e3eeb33f795204c1ca35f56c44f83227c6e66"
version = "v1.0.0"
[[projects]]
digest = "1:a30066593578732a356dc7e5d7f78d69184ca65aeeff5939241a3ab10559bb06"
name = "github.com/stretchr/testify"
packages = ["assert","require"]
packages = [
"assert",
"require",
]
pruneopts = ""
revision = "12b6f73e6084dad08a7c6e575284b177ecafbc71"
version = "v1.2.1"
[[projects]]
branch = "master"
digest = "1:2ea6df0f542cc95a5e374e9cdd81eaa599ed0d55366eef92d2f6b9efa2795c07"
name = "golang.org/x/crypto"
packages = ["ed25519","ed25519/internal/edwards25519"]
packages = [
"ed25519",
"ed25519/internal/edwards25519",
]
pruneopts = ""
revision = "432090b8f568c018896cd8a0fb0345872bbac6ce"
[[projects]]
branch = "master"
digest = "1:b4ba046df563f56fe42b6270b20039107a37e1ab47c97aa47a16f848aa5b6d9a"
name = "golang.org/x/net"
packages = ["context","context/ctxhttp","idna","publicsuffix"]
packages = [
"context",
"context/ctxhttp",
"idna",
"publicsuffix",
]
pruneopts = ""
revision = "cbe0f9307d0156177f9dd5dc85da1a31abc5f2fb"
[[projects]]
branch = "master"
digest = "1:dd57134ebff8e1a1a77c9f145a28cad8470da6bb9053d6ff2bc552ecd7f8bc92"
name = "golang.org/x/oauth2"
packages = [".","internal"]
packages = [
".",
"internal",
]
pruneopts = ""
revision = "543e37812f10c46c622c9575afd7ad22f22a12ba"
[[projects]]
branch = "master"
digest = "1:31985a0ed491dba5ba7fe92e18be008acd92ca9435ed9b35b06f3e6c00fd82cb"
name = "golang.org/x/text"
packages = ["collate","collate/build","internal/colltab","internal/gen","internal/tag","internal/triegen","internal/ucd","language","secure/bidirule","transform","unicode/bidi","unicode/cldr","unicode/norm","unicode/rangetable"]
packages = [
"collate",
"collate/build",
"internal/colltab",
"internal/gen",
"internal/tag",
"internal/triegen",
"internal/ucd",
"language",
"secure/bidirule",
"transform",
"unicode/bidi",
"unicode/cldr",
"unicode/norm",
"unicode/rangetable",
]
pruneopts = ""
revision = "4e4a3210bb54bb31f6ab2cdca2edcc0b50c420c1"
[[projects]]
digest = "1:934fb8966f303ede63aa405e2c8d7f0a427a05ea8df335dfdc1833dd4d40756f"
name = "google.golang.org/appengine"
packages = ["internal","internal/base","internal/datastore","internal/log","internal/remote_api","internal/urlfetch","urlfetch"]
packages = [
"internal",
"internal/base",
"internal/datastore",
"internal/log",
"internal/remote_api",
"internal/urlfetch",
"urlfetch",
]
pruneopts = ""
revision = "150dc57a1b433e64154302bdc40b6bb8aefa313a"
version = "v1.0.0"
[[projects]]
digest = "1:e3250d192192f02fbb143d50de437cbe967d6be7bd9fad671600942a33269d08"
name = "gopkg.in/h2non/gentleman.v2"
packages = [".","context","middleware","mux","plugin","plugins/body","plugins/bodytype","plugins/cookies","plugins/headers","plugins/multipart","plugins/query","plugins/timeout","plugins/url","utils"]
packages = [
".",
"context",
"middleware",
"mux",
"plugin",
"plugins/body",
"plugins/bodytype",
"plugins/cookies",
"plugins/headers",
"plugins/multipart",
"plugins/query",
"plugins/timeout",
"plugins/url",
"utils",
]
pruneopts = ""
revision = "e0f81be2f4064ea7aa7470e9daddd2dc8e8152c7"
version = "v2.0.3"
[[projects]]
digest = "1:be4ed0a2b15944dd777a663681a39260ed05f9c4e213017ed2e2255622c8820c"
name = "gopkg.in/square/go-jose.v2"
packages = [".","cipher","json"]
packages = [
".",
"cipher",
"json",
]
pruneopts = ""
revision = "f8f38de21b4dcd69d0413faf231983f5fd6634b1"
version = "v2.1.3"
[solve-meta]
analyzer-name = "dep"
analyzer-version = 1
inputs-digest = "bcd4dc5f3937d83e106e1a9999b3a7f5a9544ba495a3375c920688c9e73afce8"
input-imports = [
"github.com/coreos/go-oidc",
"github.com/davecgh/go-spew/spew",
"github.com/pkg/errors",
"github.com/spf13/pflag",
"github.com/stretchr/testify/assert",
"github.com/stretchr/testify/require",
"gopkg.in/h2non/gentleman.v2",
"gopkg.in/h2non/gentleman.v2/plugin",
"gopkg.in/h2non/gentleman.v2/plugins/body",
"gopkg.in/h2non/gentleman.v2/plugins/query",
"gopkg.in/h2non/gentleman.v2/plugins/timeout",
"gopkg.in/h2non/gentleman.v2/plugins/url",
]
solver-name = "gps-cdcl"
solver-version = 1

3
README.md

@ -1,3 +1,4 @@
## Basic keycloak client in go
This repo provides a basic keycloak client in go, and utilities to parse the html docs into usable schema files because I wasn't good enough to make maven give me ascii documentation. I should try again at some point. It uses swagger, so it SHOULD be doable, it was just easier at that time to write an html parser to quickly prototype something.
This repo provides a basic keycloak client in go.

12
attack_detection.go

@ -10,18 +10,18 @@ const (
)
// ClearAllLoginFailures clears any user login failures for all users. This can release temporary disabled users.
func (c *Client) ClearAllLoginFailures(realmName string) error {
return c.delete(url.Path(attackDetectionPath), url.Param("realm", realmName))
func (c *Client) ClearAllLoginFailures(accessToken string, realmName string) error {
return c.delete(accessToken, url.Path(attackDetectionPath), url.Param("realm", realmName))
}
// GetAttackDetectionStatus gets the status of a username in brute force detection.
func (c *Client) GetAttackDetectionStatus(realmName, userID string) (map[string]interface{}, error) {
func (c *Client) GetAttackDetectionStatus(accessToken string, realmName, userID string) (map[string]interface{}, error) {
var resp = map[string]interface{}{}
var err = c.get(&resp, url.Path(attackDetectionIDPath), url.Param("realm", realmName), url.Param("id", userID))
var err = c.get(accessToken, &resp, url.Path(attackDetectionIDPath), url.Param("realm", realmName), url.Param("id", userID))
return resp, err
}
// ClearUserLoginFailures clear any user login failures for the user. This can release temporary disabled user.
func (c *Client) ClearUserLoginFailures(realmName, userID string) error {
return c.delete(url.Path(attackDetectionIDPath), url.Param("realm", realmName), url.Param("id", userID))
func (c *Client) ClearUserLoginFailures(accessToken string, realmName, userID string) error {
return c.delete(accessToken, url.Path(attackDetectionIDPath), url.Param("realm", realmName), url.Param("id", userID))
}

116
authentication_management.go

@ -10,180 +10,180 @@ const (
)
// GetAuthenticatorProviders returns a list of authenticator providers.
func (c *Client) GetAuthenticatorProviders(realmName string) ([]map[string]interface{}, error) {
func (c *Client) GetAuthenticatorProviders(accessToken string, realmName string) ([]map[string]interface{}, error) {
var resp = []map[string]interface{}{}
var err = c.get(&resp, url.Path(authenticationManagementPath+"/authenticator-providers"), url.Param("realm", realmName))
var err = c.get(accessToken, &resp, url.Path(authenticationManagementPath+"/authenticator-providers"), url.Param("realm", realmName))
return resp, err
}
// GetClientAuthenticatorProviders returns a list of client authenticator providers.
func (c *Client) GetClientAuthenticatorProviders(realmName string) ([]map[string]interface{}, error) {
func (c *Client) GetClientAuthenticatorProviders(accessToken string, realmName string) ([]map[string]interface{}, error) {
var resp = []map[string]interface{}{}
var err = c.get(&resp, url.Path(authenticationManagementPath+"/client-authenticator-providers"), url.Param("realm", realmName))
var err = c.get(accessToken, &resp, url.Path(authenticationManagementPath+"/client-authenticator-providers"), url.Param("realm", realmName))
return resp, err
}
// GetAuthenticatorProviderConfig returns the authenticator provider’s configuration description.
func (c *Client) GetAuthenticatorProviderConfig(realmName, providerID string) (AuthenticatorConfigInfoRepresentation, error) {
func (c *Client) GetAuthenticatorProviderConfig(accessToken string, realmName, providerID string) (AuthenticatorConfigInfoRepresentation, error) {
var resp = AuthenticatorConfigInfoRepresentation{}
var err = c.get(&resp, url.Path(authenticationManagementPath+"/config-description/:providerID"), url.Param("realm", realmName), url.Param("providerID", providerID))
var err = c.get(accessToken, &resp, url.Path(authenticationManagementPath+"/config-description/:providerID"), url.Param("realm", realmName), url.Param("providerID", providerID))
return resp, err
}
// GetAuthenticatorConfig returns the authenticator configuration.
func (c *Client) GetAuthenticatorConfig(realmName, configID string) (AuthenticatorConfigRepresentation, error) {
func (c *Client) GetAuthenticatorConfig(accessToken string, realmName, configID string) (AuthenticatorConfigRepresentation, error) {
var resp = AuthenticatorConfigRepresentation{}
var err = c.get(&resp, url.Path(authenticationManagementPath+"/config/:id"), url.Param("realm", realmName), url.Param("id", configID))
var err = c.get(accessToken, &resp, url.Path(authenticationManagementPath+"/config/:id"), url.Param("realm", realmName), url.Param("id", configID))
return resp, err
}
// UpdateAuthenticatorConfig updates the authenticator configuration.
func (c *Client) UpdateAuthenticatorConfig(realmName, configID string, config AuthenticatorConfigRepresentation) error {
return c.put(url.Path(authenticationManagementPath+"/config/:id"), url.Param("realm", realmName), url.Param("id", configID), body.JSON(config))
func (c *Client) UpdateAuthenticatorConfig(accessToken string, realmName, configID string, config AuthenticatorConfigRepresentation) error {
return c.put(accessToken, url.Path(authenticationManagementPath+"/config/:id"), url.Param("realm", realmName), url.Param("id", configID), body.JSON(config))
}
// DeleteAuthenticatorConfig deletes the authenticator configuration.
func (c *Client) DeleteAuthenticatorConfig(realmName, configID string) error {
return c.delete(url.Path(authenticationManagementPath+"/config/:id"), url.Param("realm", realmName), url.Param("id", configID))
func (c *Client) DeleteAuthenticatorConfig(accessToken string, realmName, configID string) error {
return c.delete(accessToken, url.Path(authenticationManagementPath+"/config/:id"), url.Param("realm", realmName), url.Param("id", configID))
}
// CreateAuthenticationExecution add new authentication execution
func (c *Client) CreateAuthenticationExecution(realmName string, authExec AuthenticationExecutionRepresentation) error {
return c.post(nil, url.Path(authenticationManagementPath+"/executions"), url.Param("realm", realmName), body.JSON(authExec))
func (c *Client) CreateAuthenticationExecution(accessToken string, realmName string, authExec AuthenticationExecutionRepresentation) error {
return c.post(accessToken, nil, url.Path(authenticationManagementPath+"/executions"), url.Param("realm", realmName), body.JSON(authExec))
}
// DeleteAuthenticationExecution deletes the execution.
func (c *Client) DeleteAuthenticationExecution(realmName, executionID string) error {
return c.delete(url.Path(authenticationManagementPath+"/executions/:id"), url.Param("realm", realmName), url.Param("id", executionID))
func (c *Client) DeleteAuthenticationExecution(accessToken string, realmName, executionID string) error {
return c.delete(accessToken, url.Path(authenticationManagementPath+"/executions/:id"), url.Param("realm", realmName), url.Param("id", executionID))
}
// UpdateAuthenticationExecution update execution with new configuration.
func (c *Client) UpdateAuthenticationExecution(realmName, executionID string, authConfig AuthenticatorConfigRepresentation) error {
return c.post(nil, url.Path(authenticationManagementPath+"/executions/:id/config"), url.Param("realm", realmName), url.Param("id", executionID), body.JSON(authConfig))
func (c *Client) UpdateAuthenticationExecution(accessToken string, realmName, executionID string, authConfig AuthenticatorConfigRepresentation) error {
return c.post(accessToken, nil, url.Path(authenticationManagementPath+"/executions/:id/config"), url.Param("realm", realmName), url.Param("id", executionID), body.JSON(authConfig))
}
// LowerExecutionPriority lowers the execution’s priority.
func (c *Client) LowerExecutionPriority(realmName, executionID string) error {
return c.post(nil, url.Path(authenticationManagementPath+"/executions/:id/lower-priority"), url.Param("realm", realmName), url.Param("id", executionID))
func (c *Client) LowerExecutionPriority(accessToken string, realmName, executionID string) error {
return c.post(accessToken, nil, url.Path(authenticationManagementPath+"/executions/:id/lower-priority"), url.Param("realm", realmName), url.Param("id", executionID))
}
// RaiseExecutionPriority raise the execution’s priority.
func (c *Client) RaiseExecutionPriority(realmName, executionID string) error {
return c.post(nil, url.Path(authenticationManagementPath+"/executions/:id/raise-priority"), url.Param("realm", realmName), url.Param("id", executionID))
func (c *Client) RaiseExecutionPriority(accessToken string, realmName, executionID string) error {
return c.post(accessToken, nil, url.Path(authenticationManagementPath+"/executions/:id/raise-priority"), url.Param("realm", realmName), url.Param("id", executionID))
}
// CreateAuthenticationFlow creates a new authentication flow.
func (c *Client) CreateAuthenticationFlow(realmName string, authFlow AuthenticationFlowRepresentation) error {
return c.post(nil, url.Path(authenticationManagementPath+"/flows"), url.Param("realm", realmName), body.JSON(authFlow))
func (c *Client) CreateAuthenticationFlow(accessToken string, realmName string, authFlow AuthenticationFlowRepresentation) error {
return c.post(accessToken, nil, url.Path(authenticationManagementPath+"/flows"), url.Param("realm", realmName), body.JSON(authFlow))
}
// GetAuthenticationFlows returns a list of authentication flows.
func (c *Client) GetAuthenticationFlows(realmName string) ([]AuthenticationFlowRepresentation, error) {
func (c *Client) GetAuthenticationFlows(accessToken string, realmName string) ([]AuthenticationFlowRepresentation, error) {
var resp = []AuthenticationFlowRepresentation{}
var err = c.get(&resp, url.Path(authenticationManagementPath+"/flows"), url.Param("realm", realmName))
var err = c.get(accessToken, &resp, url.Path(authenticationManagementPath+"/flows"), url.Param("realm", realmName))
return resp, err
}
// CopyExistingAuthenticationFlow copy the existing authentication flow under a new name.
// 'flowAlias' is the name of the existing authentication flow,
// 'newName' is the new name of the authentication flow.
func (c *Client) CopyExistingAuthenticationFlow(realmName, flowAlias, newName string) error {
func (c *Client) CopyExistingAuthenticationFlow(accessToken string, realmName, flowAlias, newName string) error {
var m = map[string]string{"newName": newName}
return c.post(nil, url.Path(authenticationManagementPath+"/flows/:flowAlias/copy"), url.Param("realm", realmName), url.Param("flowAlias", flowAlias), body.JSON(m))
return c.post(accessToken, nil, url.Path(authenticationManagementPath+"/flows/:flowAlias/copy"), url.Param("realm", realmName), url.Param("flowAlias", flowAlias), body.JSON(m))
}
// GetAuthenticationExecutionForFlow returns the authentication executions for a flow.
func (c *Client) GetAuthenticationExecutionForFlow(realmName, flowAlias string) (AuthenticationExecutionInfoRepresentation, error) {
func (c *Client) GetAuthenticationExecutionForFlow(accessToken string, realmName, flowAlias string) (AuthenticationExecutionInfoRepresentation, error) {
var resp = AuthenticationExecutionInfoRepresentation{}
var err = c.get(&resp, url.Path(authenticationManagementPath+"/flows/:flowAlias/executions"), url.Param("realm", realmName), url.Param("flowAlias", flowAlias))
var err = c.get(accessToken, &resp, url.Path(authenticationManagementPath+"/flows/:flowAlias/executions"), url.Param("realm", realmName), url.Param("flowAlias", flowAlias))
return resp, err
}
// UpdateAuthenticationExecutionForFlow updates the authentication executions of a flow.
func (c *Client) UpdateAuthenticationExecutionForFlow(realmName, flowAlias string, authExecInfo AuthenticationExecutionInfoRepresentation) error {
return c.put(url.Path(authenticationManagementPath+"/flows/:flowAlias/executions"), url.Param("realm", realmName), url.Param("flowAlias", flowAlias), body.JSON(authExecInfo))
func (c *Client) UpdateAuthenticationExecutionForFlow(accessToken string, realmName, flowAlias string, authExecInfo AuthenticationExecutionInfoRepresentation) error {
return c.put(accessToken, url.Path(authenticationManagementPath+"/flows/:flowAlias/executions"), url.Param("realm", realmName), url.Param("flowAlias", flowAlias), body.JSON(authExecInfo))
}
// CreateAuthenticationExecutionForFlow add a new authentication execution to a flow.
// 'flowAlias' is the alias of the parent flow.
func (c *Client) CreateAuthenticationExecutionForFlow(realmName, flowAlias, provider string) error {
func (c *Client) CreateAuthenticationExecutionForFlow(accessToken string, realmName, flowAlias, provider string) error {
var m = map[string]string{"provider": provider}
return c.post(url.Path(authenticationManagementPath+"/flows/:flowAlias/executions/execution"), url.Param("realm", realmName), url.Param("flowAlias", flowAlias), body.JSON(m))
return c.post(accessToken, url.Path(authenticationManagementPath+"/flows/:flowAlias/executions/execution"), url.Param("realm", realmName), url.Param("flowAlias", flowAlias), body.JSON(m))
}
// CreateFlowWithExecutionForExistingFlow add a new flow with a new execution to an existing flow.
// 'flowAlias' is the alias of the parent authentication flow.
func (c *Client) CreateFlowWithExecutionForExistingFlow(realmName, flowAlias, alias, flowType, provider, description string) error {
func (c *Client) CreateFlowWithExecutionForExistingFlow(accessToken string, realmName, flowAlias, alias, flowType, provider, description string) error {
var m = map[string]string{"alias": alias, "type": flowType, "provider": provider, "description": description}
return c.post(url.Path(authenticationManagementPath+"/flows/:flowAlias/executions/flow"), url.Param("realm", realmName), url.Param("flowAlias", flowAlias), body.JSON(m))
return c.post(accessToken, url.Path(authenticationManagementPath+"/flows/:flowAlias/executions/flow"), url.Param("realm", realmName), url.Param("flowAlias", flowAlias), body.JSON(m))
}
// GetAuthenticationFlow gets the authentication flow for id.
func (c *Client) GetAuthenticationFlow(realmName, flowID string) (AuthenticationFlowRepresentation, error) {
func (c *Client) GetAuthenticationFlow(accessToken string, realmName, flowID string) (AuthenticationFlowRepresentation, error) {
var resp = AuthenticationFlowRepresentation{}
var err = c.get(&resp, url.Path(authenticationManagementPath+"/flows/:id"), url.Param("realm", realmName), url.Param("id", flowID))
var err = c.get(accessToken, &resp, url.Path(authenticationManagementPath+"/flows/:id"), url.Param("realm", realmName), url.Param("id", flowID))
return resp, err
}
// DeleteAuthenticationFlow deletes an authentication flow.
func (c *Client) DeleteAuthenticationFlow(realmName, flowID string) error {
return c.delete(url.Path(authenticationManagementPath+"/flows/:id"), url.Param("realm", realmName), url.Param("id", flowID))
func (c *Client) DeleteAuthenticationFlow(accessToken string, realmName, flowID string) error {
return c.delete(accessToken, url.Path(authenticationManagementPath+"/flows/:id"), url.Param("realm", realmName), url.Param("id", flowID))
}
// GetFormActionProviders returns a list of form action providers.
func (c *Client) GetFormActionProviders(realmName string) ([]map[string]interface{}, error) {
func (c *Client) GetFormActionProviders(accessToken string, realmName string) ([]map[string]interface{}, error) {
var resp = []map[string]interface{}{}
var err = c.get(&resp, url.Path(authenticationManagementPath+"/form-action-providers"), url.Param("realm", realmName))
var err = c.get(accessToken, &resp, url.Path(authenticationManagementPath+"/form-action-providers"), url.Param("realm", realmName))
return resp, err
}
// GetFormProviders returns a list of form providers.
func (c *Client) GetFormProviders(realmName string) ([]map[string]interface{}, error) {
func (c *Client) GetFormProviders(accessToken string, realmName string) ([]map[string]interface{}, error) {
var resp = []map[string]interface{}{}
var err = c.get(&resp, url.Path(authenticationManagementPath+"/form-providers"), url.Param("realm", realmName))
var err = c.get(accessToken, &resp, url.Path(authenticationManagementPath+"/form-providers"), url.Param("realm", realmName))
return resp, err
}
// GetConfigDescriptionForClients returns the configuration descriptions for all clients.
func (c *Client) GetConfigDescriptionForClients(realmName string) (map[string]interface{}, error) {
func (c *Client) GetConfigDescriptionForClients(accessToken string, realmName string) (map[string]interface{}, error) {
var resp = map[string]interface{}{}
var err = c.get(&resp, url.Path(authenticationManagementPath+"/per-client-config-description"), url.Param("realm", realmName))
var err = c.get(accessToken, &resp, url.Path(authenticationManagementPath+"/per-client-config-description"), url.Param("realm", realmName))
return resp, err
}
// RegisterRequiredAction register a new required action.
func (c *Client) RegisterRequiredAction(realmName, providerID, name string) error {
func (c *Client) RegisterRequiredAction(accessToken string, realmName, providerID, name string) error {
var m = map[string]string{"providerId": providerID, "name": name}
return c.post(url.Path(authenticationManagementPath+"/register-required-action"), url.Param("realm", realmName), body.JSON(m))
return c.post(accessToken, url.Path(authenticationManagementPath+"/register-required-action"), url.Param("realm", realmName), body.JSON(m))
}
// GetRequiredActions returns a list of required actions.
func (c *Client) GetRequiredActions(realmName string) ([]RequiredActionProviderRepresentation, error) {
func (c *Client) GetRequiredActions(accessToken string, realmName string) ([]RequiredActionProviderRepresentation, error) {
var resp = []RequiredActionProviderRepresentation{}
var err = c.get(&resp, url.Path(authenticationManagementPath+"/required-actions"), url.Param("realm", realmName))
var err = c.get(accessToken, &resp, url.Path(authenticationManagementPath+"/required-actions"), url.Param("realm", realmName))
return resp, err
}
// GetRequiredAction returns the required action for the alias.
func (c *Client) GetRequiredAction(realmName, actionAlias string) (RequiredActionProviderRepresentation, error) {
func (c *Client) GetRequiredAction(accessToken string, realmName, actionAlias string) (RequiredActionProviderRepresentation, error) {
var resp = RequiredActionProviderRepresentation{}
var err = c.get(&resp, url.Path(authenticationManagementPath+"/required-actions/:alias"), url.Param("realm", realmName), url.Param("alias", actionAlias))
var err = c.get(accessToken, &resp, url.Path(authenticationManagementPath+"/required-actions/:alias"), url.Param("realm", realmName), url.Param("alias", actionAlias))
return resp, err
}
// UpdateRequiredAction updates the required action.
func (c *Client) UpdateRequiredAction(realmName, actionAlias string, action RequiredActionProviderRepresentation) error {
return c.put(url.Path(authenticationManagementPath+"/required-actions/:alias"), url.Param("realm", realmName), url.Param("alias", actionAlias), body.JSON(action))
func (c *Client) UpdateRequiredAction(accessToken string, realmName, actionAlias string, action RequiredActionProviderRepresentation) error {
return c.put(accessToken, url.Path(authenticationManagementPath+"/required-actions/:alias"), url.Param("realm", realmName), url.Param("alias", actionAlias), body.JSON(action))
}
// DeleteRequiredAction deletes the required action.
func (c *Client) DeleteRequiredAction(realmName, actionAlias string) error {
return c.delete(url.Path(authenticationManagementPath+"/required-actions/:alias"), url.Param("realm", realmName), url.Param("alias", actionAlias))
func (c *Client) DeleteRequiredAction(accessToken string, realmName, actionAlias string) error {
return c.delete(accessToken, url.Path(authenticationManagementPath+"/required-actions/:alias"), url.Param("realm", realmName), url.Param("alias", actionAlias))
}
// GetUnregisteredRequiredActions returns a list of unregistered required actions.
func (c *Client) GetUnregisteredRequiredActions(realmName string) ([]map[string]interface{}, error) {
func (c *Client) GetUnregisteredRequiredActions(accessToken string, realmName string) ([]map[string]interface{}, error) {
var resp = []map[string]interface{}{}
var err = c.get(&resp, url.Path(authenticationManagementPath+"/unregistered-required-actions"), url.Param("realm", realmName))
var err = c.get(accessToken, &resp, url.Path(authenticationManagementPath+"/unregistered-required-actions"), url.Param("realm", realmName))
return resp, err
}

24
client_attribute_certificate.go

@ -12,43 +12,43 @@ const (
)
// GetKeyInfo returns the key info. idClient is the id of client (not client-id).
func (c *Client) GetKeyInfo(realmName, idClient, attr string) (CertificateRepresentation, error) {
func (c *Client) GetKeyInfo(accessToken string, realmName, idClient, attr string) (CertificateRepresentation, error) {
var resp = CertificateRepresentation{}
var err = c.get(&resp, url.Path(clientAttrCertPath), url.Param("realm", realmName), url.Param("id", idClient), url.Param("attr", attr))
var err = c.get(accessToken, &resp, url.Path(clientAttrCertPath), url.Param("realm", realmName), url.Param("id", idClient), url.Param("attr", attr))
return resp, err
}
// GetKeyStore returns a keystore file for the client, containing private key and public certificate. idClient is the id of client (not client-id).
func (c *Client) GetKeyStore(realmName, idClient, attr string, keyStoreConfig KeyStoreConfig) ([]byte, error) {
func (c *Client) GetKeyStore(accessToken string, realmName, idClient, attr string, keyStoreConfig KeyStoreConfig) ([]byte, error) {
var resp = []byte{}
var err = c.post(&resp, url.Path(clientAttrCertPath+"/download"), url.Param("realm", realmName), url.Param("id", idClient), url.Param("attr", attr), body.JSON(keyStoreConfig))
var err = c.post(accessToken, &resp, url.Path(clientAttrCertPath+"/download"), url.Param("realm", realmName), url.Param("id", idClient), url.Param("attr", attr), body.JSON(keyStoreConfig))
return resp, err
}
// GenerateCertificate generates a new certificate with new key pair. idClient is the id of client (not client-id).
func (c *Client) GenerateCertificate(realmName, idClient, attr string) (CertificateRepresentation, error) {
func (c *Client) GenerateCertificate(accessToken string, realmName, idClient, attr string) (CertificateRepresentation, error) {
var resp = CertificateRepresentation{}
var err = c.post(&resp, url.Path(clientAttrCertPath+"/generate"), url.Param("realm", realmName), url.Param("id", idClient), url.Param("attr", attr))
var err = c.post(accessToken, &resp, url.Path(clientAttrCertPath+"/generate"), url.Param("realm", realmName), url.Param("id", idClient), url.Param("attr", attr))
return resp, err
}
// GenerateKeyPairAndCertificate generates a keypair and certificate and serves the private key in a specified keystore format.
func (c *Client) GenerateKeyPairAndCertificate(realmName, idClient, attr string, keyStoreConfig KeyStoreConfig) ([]byte, error) {
func (c *Client) GenerateKeyPairAndCertificate(accessToken string, realmName, idClient, attr string, keyStoreConfig KeyStoreConfig) ([]byte, error) {
var resp = []byte{}
var err = c.post(&resp, url.Path(clientAttrCertPath+"/generate-and-download"), url.Param("realm", realmName), url.Param("id", idClient), url.Param("attr", attr), body.JSON(keyStoreConfig))
var err = c.post(accessToken, &resp, url.Path(clientAttrCertPath+"/generate-and-download"), url.Param("realm", realmName), url.Param("id", idClient), url.Param("attr", attr), body.JSON(keyStoreConfig))
return resp, err
}
// UploadCertificatePrivateKey uploads a certificate and eventually a private key.
func (c *Client) UploadCertificatePrivateKey(realmName, idClient, attr string, file []byte) (CertificateRepresentation, error) {
func (c *Client) UploadCertificatePrivateKey(accessToken string, realmName, idClient, attr string, file []byte) (CertificateRepresentation, error) {
var resp = CertificateRepresentation{}
var err = c.post(&resp, url.Path(clientAttrCertPath+"/upload"), url.Param("realm", realmName), url.Param("id", idClient), url.Param("attr", attr), body.Reader(bytes.NewReader(file)))
var err = c.post(accessToken, &resp, url.Path(clientAttrCertPath+"/upload"), url.Param("realm", realmName), url.Param("id", idClient), url.Param("attr", attr), body.Reader(bytes.NewReader(file)))
return resp, err
}
// UploadCertificate uploads only a certificate, not the private key.
func (c *Client) UploadCertificate(realmName, idClient, attr string, file []byte) (CertificateRepresentation, error) {
func (c *Client) UploadCertificate(accessToken string, realmName, idClient, attr string, file []byte) (CertificateRepresentation, error) {
var resp = CertificateRepresentation{}
var err = c.post(&resp, url.Path(clientAttrCertPath+"/upload-certificate"), url.Param("realm", realmName), url.Param("id", idClient), url.Param("attr", attr), body.Reader(bytes.NewReader(file)))
var err = c.post(accessToken, &resp, url.Path(clientAttrCertPath+"/upload-certificate"), url.Param("realm", realmName), url.Param("id", idClient), url.Param("attr", attr), body.Reader(bytes.NewReader(file)))
return resp, err
}

12
client_initial_access.go

@ -10,20 +10,20 @@ const (
)
// CreateClientInitialAccess creates a new initial access token.
func (c *Client) CreateClientInitialAccess(realmName string, access ClientInitialAccessCreatePresentation) (ClientInitialAccessPresentation, error) {
func (c *Client) CreateClientInitialAccess(accessToken string, realmName string, access ClientInitialAccessCreatePresentation) (ClientInitialAccessPresentation, error) {
var resp = ClientInitialAccessPresentation{}
var err = c.post(&resp, url.Path(clientInitialAccessPath), url.Param("realm", realmName), body.JSON(access))
var err = c.post(accessToken, &resp, url.Path(clientInitialAccessPath), url.Param("realm", realmName), body.JSON(access))
return resp, err
}
// GetClientInitialAccess returns a list of clients initial access.
func (c *Client) GetClientInitialAccess(realmName string) ([]ClientInitialAccessPresentation, error) {
func (c *Client) GetClientInitialAccess(accessToken string, realmName string) ([]ClientInitialAccessPresentation, error) {
var resp = []ClientInitialAccessPresentation{}
var err = c.get(&resp, url.Path(clientInitialAccessPath), url.Param("realm", realmName))
var err = c.get(accessToken, &resp, url.Path(clientInitialAccessPath), url.Param("realm", realmName))
return resp, err
}
// DeleteClientInitialAccess deletes the client initial access.
func (c *Client) DeleteClientInitialAccess(realmName, accessID string) error {
return c.delete(url.Path(clientInitialAccessPath+"/:id"), url.Param("realm", realmName), url.Param("id", accessID))
func (c *Client) DeleteClientInitialAccess(accessToken string, realmName, accessID string) error {
return c.delete(accessToken, url.Path(clientInitialAccessPath+"/:id"), url.Param("realm", realmName), url.Param("id", accessID))
}

4
client_registration_policy.go

@ -7,8 +7,8 @@ const (
)
// GetClientRegistrationPolicy is the base path to retrieve providers with the configProperties properly filled.
func (c *Client) GetClientRegistrationPolicy(realmName, configID string) ([]ComponentTypeRepresentation, error) {
func (c *Client) GetClientRegistrationPolicy(accessToken string, realmName, configID string) ([]ComponentTypeRepresentation, error) {
var resp = []ComponentTypeRepresentation{}
var err = c.get(&resp, url.Path(clientRegistrationPolicyPath), url.Param("realm", realmName))
var err = c.get(accessToken, &resp, url.Path(clientRegistrationPolicyPath), url.Param("realm", realmName))
return resp, err
}

12
client_role_mappings.go

@ -10,18 +10,18 @@ const (
)
// CreateClientsRoleMapping add client-level roles to the user role mapping.
func (c *Client) CreateClientsRoleMapping(realmName, groupID, clientID string, roles []RoleRepresentation) error {
return c.post(nil, url.Path(clientRoleMappingPath), url.Param("realm", realmName), url.Param("id", groupID), url.Param("client", clientID), body.JSON(roles))
func (c *Client) CreateClientsRoleMapping(accessToken string, realmName, groupID, clientID string, roles []RoleRepresentation) error {
return c.post(accessToken, nil, url.Path(clientRoleMappingPath), url.Param("realm", realmName), url.Param("id", groupID), url.Param("client", clientID), body.JSON(roles))
}
// GetClientsRoleMapping gets client-level role mappings for the user, and the app.
func (c *Client) GetClientsRoleMapping(realmName, groupID, clientID string) ([]RoleRepresentation, error) {
func (c *Client) GetClientsRoleMapping(accessToken string, realmName, groupID, clientID string) ([]RoleRepresentation, error) {
var resp = []RoleRepresentation{}
var err = c.get(&resp, url.Path(clientRoleMappingPath), url.Param("realm", realmName), url.Param("id", groupID), url.Param("client", clientID))
var err = c.get(accessToken, &resp, url.Path(clientRoleMappingPath), url.Param("realm", realmName), url.Param("id", groupID), url.Param("client", clientID))
return resp, err
}
// DeleteClientsRoleMapping deletes client-level roles from user role mapping.
func (c *Client) DeleteClientsRoleMapping(realmName, groupID, clientID string) error {
return c.delete(url.Path(clientRoleMappingPath), url.Param("realm", realmName), url.Param("id", groupID), url.Param("client", clientID))
func (c *Client) DeleteClientsRoleMapping(accessToken string, realmName, groupID, clientID string) error {
return c.delete(accessToken, url.Path(clientRoleMappingPath), url.Param("realm", realmName), url.Param("id", groupID), url.Param("client", clientID))
}

1
client_templates.go

@ -1 +0,0 @@
package keycloak

12
clients.go

@ -15,27 +15,27 @@ const (
// GetClients returns a list of clients belonging to the realm.
// Parameters: clientId (filter by clientId),
// viewableOnly (filter clients that cannot be viewed in full by admin, default="false")
func (c *Client) GetClients(realmName string, paramKV ...string) ([]ClientRepresentation, error) {
func (c *Client) GetClients(accessToken string, realmName string, paramKV ...string) ([]ClientRepresentation, error) {
if len(paramKV)%2 != 0 {
return nil, fmt.Errorf("the number of key/val parameters should be even")
}
var resp = []ClientRepresentation{}
var plugins = append(createQueryPlugins(paramKV...), url.Path(clientsPath), url.Param("realm", realmName))
var err = c.get(&resp, plugins...)
var err = c.get(accessToken, &resp, plugins...)
return resp, err
}
// GetClient get the representation of the client. idClient is the id of client (not client-id).
func (c *Client) GetClient(realmName, idClient string) (ClientRepresentation, error) {
func (c *Client) GetClient(accessToken string, realmName, idClient string) (ClientRepresentation, error) {
var resp = ClientRepresentation{}
var err = c.get(&resp, url.Path(clientIDPath), url.Param("realm", realmName), url.Param("id", idClient))
var err = c.get(accessToken, &resp, url.Path(clientIDPath), url.Param("realm", realmName), url.Param("id", idClient))
return resp, err
}
// GetSecret get the client secret. idClient is the id of client (not client-id).
func (c *Client) GetSecret(realmName, idClient string) (CredentialRepresentation, error) {
func (c *Client) GetSecret(accessToken string, realmName, idClient string) (CredentialRepresentation, error) {
var resp = CredentialRepresentation{}
var err = c.get(&resp, url.Path(clientSecret), url.Param("realm", realmName), url.Param("id", idClient))
var err = c.get(accessToken, &resp, url.Path(clientSecret), url.Param("realm", realmName), url.Param("id", idClient))
return resp, err
}

53
clients_test.go

@ -1,53 +0,0 @@
package keycloak
import (
"encoding/json"
"fmt"
"testing"
"github.com/stretchr/testify/assert"
)
func TestPlayground(t *testing.T) {
var client = initTest(t)
var clients, err = client.GetClients("master")
for _, c := range clients {
printStruct(c)
}
assert.Nil(t, err)
}
func TestCreateRealm(t *testing.T) {
var client = initTest(t)
var clients, err = client.GetClients("master")
for i, c := range clients {
fmt.Println(i, *(c.Id), *c.ClientId)
}
assert.Nil(t, err)
}
func TestGetClient(t *testing.T) {
var client = initTest(t)
var c, err = client.GetClient("318ab6db-c056-4d2f-b4f6-c0b585ee45b3", "master")
fmt.Println(*(c.Id), *c.ClientId, c.Secret)
assert.Nil(t, err)
}
func TestGetSecret(t *testing.T) {
var client = initTest(t)
var c, err = client.GetSecret("318ab6db-c056-4d2f-b4f6-c0b585ee45b3", "master")
fmt.Println(*(c.Value))
assert.Nil(t, err)
}
func printStruct(data interface{}) {
var s, err = json.Marshal(data)
if err != nil {
fmt.Println("could not marshal json")
return
}
fmt.Println(string(s))
fmt.Println()
}

1
component.go

@ -1 +0,0 @@
package keycloak

1
groups.go

@ -1 +0,0 @@
package keycloak

1
identity_providers.go

@ -1 +0,0 @@
package keycloak

BIN
integration/integration

Binary file not shown.

60
integration/integration.go

@ -22,14 +22,20 @@ func main() {
log.Fatalf("could not create keycloak client: %v", err)
}
// Get access token
accessToken, err := client.GetToken("master", "admin", "admin")
if err != nil {
log.Fatalf("could not get access token: %v", err)
}
// Delete test realm
client.DeleteRealm(tstRealm)
client.DeleteRealm(accessToken, tstRealm)
// Check existing realms
var initialRealms []keycloak.RealmRepresentation
{
var err error
initialRealms, err = client.GetRealms()
initialRealms, err = client.GetRealms(accessToken)
if err != nil {
log.Fatalf("could not get realms: %v", err)
}
@ -43,7 +49,7 @@ func main() {
// Create test realm.
{
var realm = tstRealm
var err = client.CreateRealm(keycloak.RealmRepresentation{
var err = client.CreateRealm(accessToken, keycloak.RealmRepresentation{
Realm: &realm,
})
if err != nil {
@ -54,7 +60,7 @@ func main() {
// Check getRealm.
{
var realmR, err = client.GetRealm(tstRealm)
var realmR, err = client.GetRealm(accessToken, tstRealm)
if err != nil {
log.Fatalf("could not get test realm: %v", err)
}
@ -70,7 +76,7 @@ func main() {
// Update Realm
{
var displayName = "updated realm"
var err = client.UpdateRealm(tstRealm, keycloak.RealmRepresentation{
var err = client.UpdateRealm(accessToken, tstRealm, keycloak.RealmRepresentation{
DisplayName: &displayName,
})
if err != nil {
@ -78,7 +84,7 @@ func main() {
}
// Check update
{
var realmR, err = client.GetRealm(tstRealm)
var realmR, err = client.GetRealm(accessToken, tstRealm)
if err != nil {
log.Fatalf("could not get test realm: %v", err)
}
@ -91,7 +97,7 @@ func main() {
// Count users.
{
var nbrUser, err = client.CountUsers(tstRealm)
var nbrUser, err = client.CountUsers(accessToken, tstRealm)
if err != nil {
log.Fatalf("could not count users: %v", err)
}
@ -105,7 +111,7 @@ func main() {
for _, u := range tstUsers {
var username = strings.ToLower(u.firstname + "." + u.lastname)
var email = username + "@cloudtrust.ch"
var err = client.CreateUser(tstRealm, keycloak.UserRepresentation{
var err = client.CreateUser(accessToken, tstRealm, keycloak.UserRepresentation{
Username: &username,
FirstName: &u.firstname,
LastName: &u.lastname,
@ -117,7 +123,7 @@ func main() {
}
// Check that all users where created.
{
var nbrUser, err = client.CountUsers(tstRealm)
var nbrUser, err = client.CountUsers(accessToken, tstRealm)
if err != nil {
log.Fatalf("could not count users: %v", err)
}
@ -132,7 +138,7 @@ func main() {
{
{
// No parameters.
var users, err = client.GetUsers(tstRealm)
var users, err = client.GetUsers(accessToken, tstRealm)
if err != nil {
log.Fatalf("could not get users: %v", err)
}
@ -142,7 +148,7 @@ func main() {
}
{
// email.
var users, err = client.GetUsers(tstRealm, "email", "john.doe@cloudtrust.ch")
var users, err = client.GetUsers(accessToken, tstRealm, "email", "john.doe@cloudtrust.ch")
if err != nil {
log.Fatalf("could not get users: %v", err)
}
@ -152,7 +158,7 @@ func main() {
}
{
// firstname.
var users, err = client.GetUsers(tstRealm, "firstName", "John")
var users, err = client.GetUsers(accessToken, tstRealm, "firstName", "John")
if err != nil {
log.Fatalf("could not get users: %v", err)
}
@ -163,7 +169,7 @@ func main() {
}
{
// lastname.
var users, err = client.GetUsers(tstRealm, "lastName", "Wells")
var users, err = client.GetUsers(accessToken, tstRealm, "lastName", "Wells")
if err != nil {
log.Fatalf("could not get users: %v", err)
}
@ -173,7 +179,7 @@ func main() {
}
{
// username.
var users, err = client.GetUsers(tstRealm, "username", "lucia.nelson")
var users, err = client.GetUsers(accessToken, tstRealm, "username", "lucia.nelson")
if err != nil {
log.Fatalf("could not get users: %v", err)
}
@ -183,7 +189,7 @@ func main() {
}
{
// first.
var users, err = client.GetUsers(tstRealm, "max", "7")
var users, err = client.GetUsers(accessToken, tstRealm, "max", "7")
if err != nil {
log.Fatalf("could not get users: %v", err)
}
@ -193,7 +199,7 @@ func main() {
}
{
// search.
var users, err = client.GetUsers(tstRealm, "search", "le")
var users, err = client.GetUsers(accessToken, tstRealm, "search", "le")
if err != nil {
log.Fatalf("could not get users: %v", err)
}
@ -209,7 +215,7 @@ func main() {
// Get user ID.
var userID string
{
var users, err = client.GetUsers(tstRealm, "search", "Maria")
var users, err = client.GetUsers(accessToken, tstRealm, "search", "Maria")
if err != nil {
log.Fatalf("could not get Maria: %v", err)
}
@ -226,7 +232,7 @@ func main() {
var updatedLastname = "updated"
{
var err = client.UpdateUser(tstRealm, userID, keycloak.UserRepresentation{
var err = client.UpdateUser(accessToken, tstRealm, userID, keycloak.UserRepresentation{
FirstName: &username,
LastName: &updatedLastname,
})
@ -236,7 +242,7 @@ func main() {
}
// Check that user was updated.
{
var users, err = client.GetUsers(tstRealm, "search", "Maria")
var users, err = client.GetUsers(accessToken, tstRealm, "search", "Maria")
if err != nil {
log.Fatalf("could not get Maria: %v", err)
}
@ -255,7 +261,7 @@ func main() {
// Get user ID.
var userID string
{
var users, err = client.GetUsers(tstRealm, "search", "Toni")
var users, err = client.GetUsers(accessToken, tstRealm, "search", "Toni")
if err != nil {
log.Fatalf("could not get Toni: %v", err)
}
@ -269,14 +275,14 @@ func main() {
}
// Delete user.
{
var err = client.DeleteUser(tstRealm, userID)
var err = client.DeleteUser(accessToken, tstRealm, userID)
if err != nil {
log.Fatalf("could not delete user: %v", err)
}
}
// Check that user was deleted.
{
var nbrUser, err = client.CountUsers(tstRealm)
var nbrUser, err = client.CountUsers(accessToken, tstRealm)
if err != nil {
log.Fatalf("could not count users: %v", err)
}
@ -289,13 +295,13 @@ func main() {
// Delete test realm.
{
var err = client.DeleteRealm(tstRealm)
var err = client.DeleteRealm(accessToken, tstRealm)
if err != nil {
log.Fatalf("could not delete test realm: %v", err)
}
// Check that the realm was deleted.
{
var realms, err = client.GetRealms()
var realms, err = client.GetRealms(accessToken)
if err != nil {
log.Fatalf("could not get realms: %v", err)
}
@ -331,15 +337,11 @@ func (c *Client) DeleteUser(realmName, userID string) error {
*/
func getKeycloakConfig() *keycloak.Config {
var adr = pflag.String("url", "localhost:8080", "keycloak address")
var username = pflag.String("username", "admin", "keycloak username")
var password = pflag.String("password", "admin", "keycloak password")
var adr = pflag.String("url", "http://localhost:8080", "keycloak address")
pflag.Parse()
return &keycloak.Config{
Addr: *adr,
Username: *username,
Password: *password,
Timeout: 10 * time.Second,
}
}

1
key.go

@ -1 +0,0 @@
package keycloak

123
keycloak_client.go

@ -17,18 +17,13 @@ import (
// Config is the keycloak client http config.
type Config struct {
Addr string
Username string
Password string
Timeout time.Duration
Addr string
Timeout time.Duration
}
// Client is the keycloak client.
type Client struct {
username string
password string
accessToken string
oidcProvider *oidc.Provider
url *url.URL
httpClient *gentleman.Client
}
@ -43,44 +38,28 @@ func New(config Config) (*Client, error) {
}
}
// if u.Scheme != "http" {
// return nil, fmt.Errorf("protocol not supported, your address must start with http://, not %v", u.Scheme)
// }
var httpClient = gentleman.New()
{
httpClient = httpClient.URL(u.String())
httpClient = httpClient.Use(timeout.Request(config.Timeout))
}
var oidcProvider *oidc.Provider
{
var err error
var issuer = fmt.Sprintf("%s/auth/realms/master", u.String())
oidcProvider, err = oidc.NewProvider(context.Background(), issuer)
if err != nil {
return nil, errors.Wrap(err, "could not create oidc provider")
}
}
return &Client{
username: config.Username,
password: config.Password,
oidcProvider: oidcProvider,
httpClient: httpClient,
url: u,
httpClient: httpClient,
}, nil
}
// getToken get a token from keycloak.
func (c *Client) getToken() error {
// getToken returns a valid token from keycloak.
func (c *Client) GetToken(realm string, username string, password string) (string, error) {
var req *gentleman.Request
{
var authPath = "/auth/realms/master/protocol/openid-connect/token"
var authPath = fmt.Sprintf("/auth/realms/%s/protocol/openid-connect/token", realm)
req = c.httpClient.Post()
req = req.SetHeader("Content-Type", "application/x-www-form-urlencoded")
req = req.Path(authPath)
req = req.Type("urlencoded")
req = req.BodyString(fmt.Sprintf("username=%s&password=%s&grant_type=password&client_id=admin-cli", c.username, c.password))
req = req.BodyString(fmt.Sprintf("username=%s&password=%s&grant_type=password&client_id=admin-cli", username, password))
}
var resp *gentleman.Response
@ -88,17 +67,20 @@ func (c *Client) getToken() error {
var err error
resp, err = req.Do()
if err != nil {
return errors.Wrap(err, "could not get token")
return "", errors.Wrap(err, "could not get token")
}
}
defer resp.Close()
titi := string(resp.Bytes())
fmt.Printf(titi)
var unmarshalledBody map[string]interface{}
{
var err error
err = resp.JSON(&unmarshalledBody)
if err != nil {
return errors.Wrap(err, "could not unmarshal response")
return "", errors.Wrap(err, "could not unmarshal response")
}
}
@ -107,28 +89,37 @@ func (c *Client) getToken() error {
var ok bool
accessToken, ok = unmarshalledBody["access_token"]
if !ok {
return fmt.Errorf("could not find access token in response body")
return "", fmt.Errorf("could not find access token in response body")
}
}
c.accessToken = accessToken.(string)
return nil
return accessToken.(string), nil
}
// verifyToken token verify a token. It returns an error it is malformed, expired,...
func (c *Client) verifyToken() error {
var v = c.oidcProvider.Verifier(&oidc.Config{SkipClientIDCheck: true})
func (c *Client) VerifyToken(realmName string, accessToken string) error {
var oidcProvider *oidc.Provider
{
var err error
var issuer = fmt.Sprintf("%s/auth/realms/%s", c.url.String(), realmName)
oidcProvider, err = oidc.NewProvider(context.Background(), issuer)
if err != nil {
return errors.Wrap(err, "could not create oidc provider")
}
}
var v = oidcProvider.Verifier(&oidc.Config{SkipClientIDCheck: true})
var err error
_, err = v.Verify(context.Background(), c.accessToken)
_, err = v.Verify(context.Background(), accessToken)
return err
}
// get is a HTTP get method.
func (c *Client) get(data interface{}, plugins ...plugin.Plugin) error {
func (c *Client) get(accessToken string, data interface{}, plugins ...plugin.Plugin) error {
var req = c.httpClient.Get()
req = applyPlugins(req, c.accessToken, plugins...)
req = applyPlugins(req, accessToken, plugins...)
var resp *gentleman.Response
{
@ -140,16 +131,9 @@ func (c *Client) get(data interface{}, plugins ...plugin.Plugin) error {
switch {
case resp.StatusCode == http.StatusUnauthorized:
// If the token is not valid (expired, ...) ask a new one.
if err = c.verifyToken(); err != nil {
var err = c.getToken()
if err != nil {
return errors.Wrap(err, "could not get token: %v")
}
}
return c.get(data, plugins...)
return fmt.Errorf("unauthorized request: '%v': %v", resp.RawResponse.Status, resp.String())
case resp.StatusCode >= 400:
return fmt.Errorf("invalid status code: '%v': %v", resp.RawResponse.Status, string(resp.Bytes()))
return fmt.Errorf("invalid status code: '%v': %v", resp.RawResponse.Status, resp.String())
case resp.StatusCode >= 200:
switch resp.Header.Get("Content-Type") {
case "application/json":
@ -166,9 +150,9 @@ func (c *Client) get(data interface{}, plugins ...plugin.Plugin) error {
}
}
func (c *Client) post(data interface{}, plugins ...plugin.Plugin) error {
func (c *Client) post(accessToken string, data interface{}, plugins ...plugin.Plugin) error {
var req = c.httpClient.Post()
req = applyPlugins(req, c.accessToken, plugins...)
req = applyPlugins(req, accessToken, plugins...)
var resp *gentleman.Response
{
var err error
@ -179,14 +163,7 @@ func (c *Client) post(data interface{}, plugins ...plugin.Plugin) error {
switch {
case resp.StatusCode == http.StatusUnauthorized:
// If the token is not valid (expired, ...) ask a new one.
if err = c.verifyToken(); err != nil {
var err = c.getToken()
if err != nil {
return errors.Wrap(err, "could not get token")
}
}
return c.post(data, plugins...)
return fmt.Errorf("unauthorized request: '%v': %v", resp.RawResponse.Status, resp.String())
case resp.StatusCode >= 400:
return fmt.Errorf("invalid status code: '%v': %v", resp.RawResponse.Status, string(resp.Bytes()))
case resp.StatusCode >= 200:
@ -197,7 +174,7 @@ func (c *Client) post(data interface{}, plugins ...plugin.Plugin) error {
data = resp.Bytes()
return nil
default:
return fmt.Errorf("unkown http content-type: %v", resp.Header.Get("Content-Type"))
return nil
}
default:
return fmt.Errorf("unknown response status code: %v", resp.StatusCode)
@ -205,9 +182,9 @@ func (c *Client) post(data interface{}, plugins ...plugin.Plugin) error {
}
}
func (c *Client) delete(plugins ...plugin.Plugin) error {
func (c *Client) delete(accessToken string, plugins ...plugin.Plugin) error {
var req = c.httpClient.Delete()
req = applyPlugins(req, c.accessToken, plugins...)
req = applyPlugins(req, accessToken, plugins...)
var resp *gentleman.Response
{
@ -219,14 +196,7 @@ func (c *Client) delete(plugins ...plugin.Plugin) error {
switch {
case resp.StatusCode == http.StatusUnauthorized:
// If the token is not valid (expired, ...) ask a new one.
if err = c.verifyToken(); err != nil {
var err = c.getToken()
if err != nil {
return errors.Wrap(err, "could not get token")
}
}
return c.delete(plugins...)
return fmt.Errorf("unauthorized request: '%v': %v", resp.RawResponse.Status, resp.String())
case resp.StatusCode >= 400:
return fmt.Errorf("invalid status code: '%v': %v", resp.RawResponse.Status, string(resp.Bytes()))
case resp.StatusCode >= 200:
@ -237,9 +207,9 @@ func (c *Client) delete(plugins ...plugin.Plugin) error {
}
}
func (c *Client) put(plugins ...plugin.Plugin) error {
func (c *Client) put(accessToken string, plugins ...plugin.Plugin) error {
var req = c.httpClient.Put()
req = applyPlugins(req, c.accessToken, plugins...)
req = applyPlugins(req, accessToken, plugins...)
var resp *gentleman.Response
{
@ -251,14 +221,7 @@ func (c *Client) put(plugins ...plugin.Plugin) error {
switch {
case resp.StatusCode == http.StatusUnauthorized:
// If the token is not valid (expired, ...) ask a new one.
if err = c.verifyToken(); err != nil {
var err = c.getToken()
if err != nil {
return errors.Wrap(err, "could not get token: %v")
}
}
return c.put(plugins...)
return fmt.Errorf("unauthorized request: '%v': %v", resp.RawResponse.Status, resp.String())
case resp.StatusCode >= 400:
return fmt.Errorf("invalid status code: '%v': %v", resp.RawResponse.Status, string(resp.Bytes()))
case resp.StatusCode >= 200:

40
keycloak_client_test.go

@ -1,40 +0,0 @@
package keycloak
import (
"flag"
"fmt"
"os"
"testing"
"time"
"github.com/stretchr/testify/require"
)
var (
hostPort = flag.String("hostport", "10.244.18.2:80", "keycloak host:port")
username = flag.String("username", "admin", "keycloak user name")
password = flag.String("password", "admin", "keycloak password")
to = flag.Int("timeout", 20, "timeout in seconds")
)
func TestMain(m *testing.M) {
flag.Parse()
result := m.Run()
os.Exit(result)
}
func initTest(t *testing.T) *Client {
var config = Config{
Addr: fmt.Sprintf("http://%s", *hostPort),
Username: *username,
Password: *password,
Timeout: time.Duration(*to) * time.Second,
}
var client *Client
{
var err error
client, err = New(config)
require.Nil(t, err, "could not create client")
}
return client
}

24
realm.go

@ -13,39 +13,39 @@ const (
// GetRealms get the top level represention of all the realms. Nested information like users are
// not included.
func (c *Client) GetRealms() ([]RealmRepresentation, error) {
func (c *Client) GetRealms(accessToken string) ([]RealmRepresentation, error){
var resp = []RealmRepresentation{}
var err = c.get(&resp, url.Path(realmRootPath))
var err = c.get(accessToken, &resp, url.Path(realmRootPath))
return resp, err
}
// CreateRealm creates the realm from its RealmRepresentation.
func (c *Client) CreateRealm(realm RealmRepresentation) error {
return c.post(nil, url.Path(realmRootPath), body.JSON(realm))
func (c *Client) CreateRealm(accessToken string, realm RealmRepresentation) error {
return c.post(accessToken, nil, url.Path(realmRootPath), body.JSON(realm))
}
// GetRealm get the top level represention of the realm. Nested information like users are
// not included.
func (c *Client) GetRealm(realmName string) (RealmRepresentation, error) {
func (c *Client) GetRealm(accessToken string, realmName string) (RealmRepresentation, error) {
var resp = RealmRepresentation{}
var err = c.get(&resp, url.Path(realmPath), url.Param("realm", realmName))
var err = c.get(accessToken, &resp, url.Path(realmPath), url.Param("realm", realmName))
return resp, err
}
// UpdateRealm update the top lovel information of the realm. Any user, role or client information
// from the realm representation will be ignored.
func (c *Client) UpdateRealm(realmName string, realm RealmRepresentation) error {
return c.put(url.Path(realmPath), url.Param("realm", realmName), body.JSON(realm))
func (c *Client) UpdateRealm(accessToken string, realmName string, realm RealmRepresentation) error {
return c.put(accessToken, url.Path(realmPath), url.Param("realm", realmName), body.JSON(realm))
}
// DeleteRealm deletes the realm.
func (c *Client) DeleteRealm(realmName string) error {
return c.delete(url.Path(realmPath), url.Param("realm", realmName))
func (c *Client) DeleteRealm(accessToken string, realmName string) error {
return c.delete(accessToken, url.Path(realmPath), url.Param("realm", realmName))
}
// ExportRealm recovers the full realm.
func (c *Client) ExportRealm(realmName string) (RealmRepresentation, error) {
func (c *Client) ExportRealm(accessToken string, realmName string) (RealmRepresentation, error) {
var resp = RealmRepresentation{}
var err = c.get(&resp, url.Path(exportRealmPath), url.Param("realm", realmName))
var err = c.get(accessToken, &resp, url.Path(exportRealmPath), url.Param("realm", realmName))
return resp, err
}

25
realm_test.go

@ -1,25 +0,0 @@
package keycloak
import (
"testing"
"time"
"github.com/davecgh/go-spew/spew"
"github.com/stretchr/testify/require"
)
func TestExportRealms(t *testing.T) {
var client, err = New(Config{
Addr: "http://keycloak:80",
Username: "admin",
Password: "admin",
Timeout: 10 * time.Second,
})
require.Nil(t, err, "Err wasnt nil!", err)
{
var realm, err = client.ExportRealm("master")
require.Nil(t, err, "Err isnt nil!", err)
spew.Dump(realm)
}
}

1
realms_admin.go

@ -1 +0,0 @@
package keycloak

1
role_mapper.go

@ -1 +0,0 @@
package keycloak

1
roles.go

@ -1 +0,0 @@
package keycloak

1
root.go

@ -1 +0,0 @@
package keycloak

1
scope_mappings.go

@ -1 +0,0 @@
package keycloak

1
user_storage_provider.go

@ -1 +0,0 @@
package keycloak

24
users.go

@ -17,42 +17,42 @@ const (
// Parameters: email, first (paging offset, int), firstName, lastName, username,
// max (maximum result size, default = 100),
// search (string contained in username, firstname, lastname or email)
func (c *Client) GetUsers(realmName string, paramKV ...string) ([]UserRepresentation, error) {
func (c *Client) GetUsers(accessToken string, realmName string, paramKV ...string) ([]UserRepresentation, error) {
if len(paramKV)%2 != 0 {
return nil, fmt.Errorf("the number of key/val parameters should be even")
}
var resp = []UserRepresentation{}
var plugins = append(createQueryPlugins(paramKV...), url.Path(userPath), url.Param("realm", realmName))
var err = c.get(&resp, plugins...)
var err = c.get(accessToken, &resp, plugins...)
return resp, err
}
// CreateUser creates the user from its UserRepresentation. The username must be unique.
func (c *Client) CreateUser(realmName string, user UserRepresentation) error {
return c.post(nil, url.Path(userPath), url.Param("realm", realmName), body.JSON(user))
func (c *Client) CreateUser(accessToken string, realmName string, user UserRepresentation) error {
return c.post(accessToken, nil, url.Path(userPath), url.Param("realm", realmName), body.JSON(user))
}
// CountUsers returns the number of users in the realm.
func (c *Client) CountUsers(realmName string) (int, error) {
func (c *Client) CountUsers(accessToken string, realmName string) (int, error) {
var resp = 0
var err = c.get(&resp, url.Path(userCountPath), url.Param("realm", realmName))
var err = c.get(accessToken, &resp, url.Path(userCountPath), url.Param("realm", realmName))
return resp, err
}
// GetUser get the represention of the user.
func (c *Client) GetUser(realmName, userID string) (UserRepresentation, error) {
func (c *Client) GetUser(accessToken string, realmName, userID string) (UserRepresentation, error) {
var resp = UserRepresentation{}
var err = c.get(&resp, url.Path(userIDPath), url.Param("realm", realmName), url.Param("id", userID))
var err = c.get(accessToken, &resp, url.Path(userIDPath), url.Param("realm", realmName), url.Param("id", userID))
return resp, err
}
// UpdateUser updates the user.
func (c *Client) UpdateUser(realmName, userID string, user UserRepresentation) error {
return c.put(url.Path(userIDPath), url.Param("realm", realmName), url.Param("id", userID), body.JSON(user))
func (c *Client) UpdateUser(accessToken string, realmName, userID string, user UserRepresentation) error {
return c.put(accessToken, url.Path(userIDPath), url.Param("realm", realmName), url.Param("id", userID), body.JSON(user))
}
// DeleteUser deletes the user.
func (c *Client) DeleteUser(realmName, userID string) error {
return c.delete(url.Path(userIDPath), url.Param("realm", realmName), url.Param("id", userID))
func (c *Client) DeleteUser(accessToken string, realmName, userID string) error {
return c.delete(accessToken, url.Path(userIDPath), url.Param("realm", realmName), url.Param("id", userID))
}

23
users_test.go

@ -1,23 +0,0 @@
package keycloak
import (
"fmt"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestGetUsers(t *testing.T) {
var c = initTest(t)
var users []UserRepresentation
{
var err error
users, err = c.GetUsers("master")
require.Nil(t, err, "could not get users")
}
for _, i := range users {
fmt.Println(i.Credentials)
assert.NotZero(t, *i.Username)
}
}
Loading…
Cancel
Save