// Package gocloak is a golang keycloak adaptor. package gocloak import ( "context" "encoding/base64" "fmt" "io" "net/http" "net/url" "strings" "sync" "time" "github.com/go-resty/resty/v2" "github.com/golang-jwt/jwt/v5" "github.com/opentracing/opentracing-go" "github.com/pkg/errors" "github.com/segmentio/ksuid" "github.com/Nerzal/gocloak/v13/pkg/jwx" ) // GoCloak provides functionalities to talk to Keycloak. type GoCloak struct { basePath string certsCache sync.Map certsLock sync.Mutex restyClient *resty.Client Config struct { CertsInvalidateTime time.Duration authAdminRealms string authRealms string tokenEndpoint string revokeEndpoint string logoutEndpoint string openIDConnect string attackDetection string } } const ( adminClientID string = "admin-cli" urlSeparator string = "/" ) func makeURL(path ...string) string { return strings.Join(path, urlSeparator) } // GetRequest returns a request for calling endpoints. func (g *GoCloak) GetRequest(ctx context.Context) *resty.Request { var err HTTPErrorResponse return injectTracingHeaders( ctx, g.restyClient.R(). SetContext(ctx). SetError(&err), ) } // GetRequestWithBearerAuthNoCache returns a JSON base request configured with an auth token and no-cache header. func (g *GoCloak) GetRequestWithBearerAuthNoCache(ctx context.Context, token string) *resty.Request { return g.GetRequest(ctx). SetAuthToken(token). SetHeader("Content-Type", "application/json"). SetHeader("Cache-Control", "no-cache") } // GetRequestWithBearerAuth returns a JSON base request configured with an auth token. func (g *GoCloak) GetRequestWithBearerAuth(ctx context.Context, token string) *resty.Request { return g.GetRequest(ctx). SetAuthToken(token). SetHeader("Content-Type", "application/json") } // GetRequestWithBearerAuthXMLHeader returns an XML base request configured with an auth token. func (g *GoCloak) GetRequestWithBearerAuthXMLHeader(ctx context.Context, token string) *resty.Request { return g.GetRequest(ctx). SetAuthToken(token). SetHeader("Content-Type", "application/xml;charset=UTF-8") } // GetRequestWithBasicAuth returns a form data base request configured with basic auth. func (g *GoCloak) GetRequestWithBasicAuth(ctx context.Context, clientID, clientSecret string) *resty.Request { req := g.GetRequest(ctx). SetHeader("Content-Type", "application/x-www-form-urlencoded") // Public client doesn't require Basic Auth if len(clientID) > 0 && len(clientSecret) > 0 { httpBasicAuth := base64.StdEncoding.EncodeToString([]byte(clientID + ":" + clientSecret)) req.SetHeader("Authorization", "Basic "+httpBasicAuth) } return req } func (g *GoCloak) getRequestingParty(ctx context.Context, token string, realm string, options RequestingPartyTokenOptions, res interface{}) (*resty.Response, error) { return g.GetRequestWithBearerAuth(ctx, token). SetFormData(options.FormData()). SetFormDataFromValues(url.Values{"permission": PStringSlice(options.Permissions)}). SetResult(&res). Post(g.getRealmURL(realm, g.Config.tokenEndpoint)) } func checkForError(resp *resty.Response, err error, errMessage string) error { if err != nil { return &APIError{ Code: 0, Message: errors.Wrap(err, errMessage).Error(), Type: ParseAPIErrType(err), } } if resp == nil { return &APIError{ Message: "empty response", Type: ParseAPIErrType(err), } } if resp.IsError() { var msg string if e, ok := resp.Error().(*HTTPErrorResponse); ok && e.NotEmpty() { msg = fmt.Sprintf("%s: %s", resp.Status(), e) } else { msg = resp.Status() } return &APIError{ Code: resp.StatusCode(), Message: msg, Type: ParseAPIErrType(err), } } return nil } func getID(resp *resty.Response) string { header := resp.Header().Get("Location") splittedPath := strings.Split(header, urlSeparator) return splittedPath[len(splittedPath)-1] } func findUsedKey(usedKeyID string, keys []CertResponseKey) *CertResponseKey { for _, key := range keys { if *(key.Kid) == usedKeyID { return &key } } return nil } func injectTracingHeaders(ctx context.Context, req *resty.Request) *resty.Request { // look for span in context, do nothing if span is not found span := opentracing.SpanFromContext(ctx) if span == nil { return req } // look for tracer in context, use global tracer if not found tracer, ok := ctx.Value(tracerContextKey).(opentracing.Tracer) if !ok || tracer == nil { tracer = opentracing.GlobalTracer() } // inject tracing header into request err := tracer.Inject(span.Context(), opentracing.HTTPHeaders, opentracing.HTTPHeadersCarrier(req.Header)) if err != nil { return req } return req } // =============== // Keycloak client // =============== // NewClient creates a new Client func NewClient(basePath string, options ...func(*GoCloak)) *GoCloak { c := GoCloak{ basePath: strings.TrimRight(basePath, urlSeparator), restyClient: resty.New(), } c.Config.CertsInvalidateTime = 10 * time.Minute c.Config.authAdminRealms = makeURL("admin", "realms") c.Config.authRealms = makeURL("realms") c.Config.tokenEndpoint = makeURL("protocol", "openid-connect", "token") c.Config.logoutEndpoint = makeURL("protocol", "openid-connect", "logout") c.Config.revokeEndpoint = makeURL("protocol", "openid-connect", "revoke") c.Config.openIDConnect = makeURL("protocol", "openid-connect") c.Config.attackDetection = makeURL("attack-detection", "brute-force") for _, option := range options { option(&c) } return &c } // RestyClient returns the internal resty g. // This can be used to configure the g. func (g *GoCloak) RestyClient() *resty.Client { return g.restyClient } // SetRestyClient overwrites the internal resty g. func (g *GoCloak) SetRestyClient(restyClient *resty.Client) { g.restyClient = restyClient } func (g *GoCloak) getRealmURL(realm string, path ...string) string { path = append([]string{g.basePath, g.Config.authRealms, realm}, path...) return makeURL(path...) } func (g *GoCloak) getAdminRealmURL(realm string, path ...string) string { path = append([]string{g.basePath, g.Config.authAdminRealms, realm}, path...) return makeURL(path...) } func (g *GoCloak) getAttackDetectionURL(realm string, user string, path ...string) string { path = append([]string{g.basePath, g.Config.authAdminRealms, realm, g.Config.attackDetection, user}, path...) return makeURL(path...) } // ==== Functional Options === // SetLegacyWildFlySupport maintain legacy WildFly support. func SetLegacyWildFlySupport() func(g *GoCloak) { return func(g *GoCloak) { g.Config.authAdminRealms = makeURL("auth", "admin", "realms") g.Config.authRealms = makeURL("auth", "realms") } } // SetAuthRealms sets the auth realm func SetAuthRealms(url string) func(g *GoCloak) { return func(g *GoCloak) { g.Config.authRealms = url } } // SetAuthAdminRealms sets the auth admin realm func SetAuthAdminRealms(url string) func(g *GoCloak) { return func(g *GoCloak) { g.Config.authAdminRealms = url } } // SetTokenEndpoint sets the token endpoint func SetTokenEndpoint(url string) func(g *GoCloak) { return func(g *GoCloak) { g.Config.tokenEndpoint = url } } // SetRevokeEndpoint sets the revoke endpoint func SetRevokeEndpoint(url string) func(g *GoCloak) { return func(g *GoCloak) { g.Config.revokeEndpoint = url } } // SetLogoutEndpoint sets the logout func SetLogoutEndpoint(url string) func(g *GoCloak) { return func(g *GoCloak) { g.Config.logoutEndpoint = url } } // SetOpenIDConnectEndpoint sets the logout func SetOpenIDConnectEndpoint(url string) func(g *GoCloak) { return func(g *GoCloak) { g.Config.openIDConnect = url } } // SetCertCacheInvalidationTime sets the logout func SetCertCacheInvalidationTime(duration time.Duration) func(g *GoCloak) { return func(g *GoCloak) { g.Config.CertsInvalidateTime = duration } } // GetServerInfo fetches the server info. func (g *GoCloak) GetServerInfo(ctx context.Context, accessToken string) (*ServerInfoRepresentation, error) { errMessage := "could not get server info" var result *ServerInfoRepresentation resp, err := g.GetRequestWithBearerAuth(ctx, accessToken). SetResult(&result). Get(makeURL(g.basePath, "admin", "serverinfo")) if err := checkForError(resp, err, errMessage); err != nil { return nil, err } return result, nil } // GetUserInfo calls the UserInfo endpoint func (g *GoCloak) GetUserInfo(ctx context.Context, accessToken, realm string) (*UserInfo, error) { const errMessage = "could not get user info" var result UserInfo resp, err := g.GetRequestWithBearerAuth(ctx, accessToken). SetResult(&result). Get(g.getRealmURL(realm, g.Config.openIDConnect, "userinfo")) if err := checkForError(resp, err, errMessage); err != nil { return nil, err } return &result, nil } // GetRawUserInfo calls the UserInfo endpoint and returns a raw json object func (g *GoCloak) GetRawUserInfo(ctx context.Context, accessToken, realm string) (map[string]interface{}, error) { const errMessage = "could not get user info" var result map[string]interface{} resp, err := g.GetRequestWithBearerAuth(ctx, accessToken). SetResult(&result). Get(g.getRealmURL(realm, g.Config.openIDConnect, "userinfo")) if err := checkForError(resp, err, errMessage); err != nil { return nil, err } return result, nil } func (g *GoCloak) getNewCerts(ctx context.Context, realm string) (*CertResponse, error) { const errMessage = "could not get newCerts" var result CertResponse resp, err := g.GetRequest(ctx). SetResult(&result). Get(g.getRealmURL(realm, g.Config.openIDConnect, "certs")) if err := checkForError(resp, err, errMessage); err != nil { return nil, err } return &result, nil } // GetCerts fetches certificates for the given realm from the public /open-id-connect/certs endpoint func (g *GoCloak) GetCerts(ctx context.Context, realm string) (*CertResponse, error) { const errMessage = "could not get certs" if cert, ok := g.certsCache.Load(realm); ok { return cert.(*CertResponse), nil } g.certsLock.Lock() defer g.certsLock.Unlock() if cert, ok := g.certsCache.Load(realm); ok { return cert.(*CertResponse), nil } cert, err := g.getNewCerts(ctx, realm) if err != nil { return nil, errors.Wrap(err, errMessage) } g.certsCache.Store(realm, cert) time.AfterFunc(g.Config.CertsInvalidateTime, func() { g.certsCache.Delete(realm) }) return cert, nil } // GetIssuer gets the issuer of the given realm func (g *GoCloak) GetIssuer(ctx context.Context, realm string) (*IssuerResponse, error) { const errMessage = "could not get issuer" var result IssuerResponse resp, err := g.GetRequest(ctx). SetResult(&result). Get(g.getRealmURL(realm)) if err := checkForError(resp, err, errMessage); err != nil { return nil, err } return &result, nil } // RetrospectToken calls the openid-connect introspect endpoint func (g *GoCloak) RetrospectToken(ctx context.Context, accessToken, clientID, clientSecret, realm string) (*IntroSpectTokenResult, error) { const errMessage = "could not introspect requesting party token" var result IntroSpectTokenResult resp, err := g.GetRequestWithBasicAuth(ctx, clientID, clientSecret). SetFormData(map[string]string{ "token_type_hint": "requesting_party_token", "token": accessToken, }). SetResult(&result). Post(g.getRealmURL(realm, g.Config.tokenEndpoint, "introspect")) if err := checkForError(resp, err, errMessage); err != nil { return nil, err } return &result, nil } func (g *GoCloak) decodeAccessTokenWithClaims(ctx context.Context, accessToken, realm string, claims jwt.Claims) (*jwt.Token, error) { const errMessage = "could not decode access token" accessToken = strings.Replace(accessToken, "Bearer ", "", 1) decodedHeader, err := jwx.DecodeAccessTokenHeader(accessToken) if err != nil { return nil, errors.Wrap(err, errMessage) } certResult, err := g.GetCerts(ctx, realm) if err != nil { return nil, errors.Wrap(err, errMessage) } if certResult.Keys == nil { return nil, errors.Wrap(errors.New("there is no keys to decode the token"), errMessage) } usedKey := findUsedKey(decodedHeader.Kid, *certResult.Keys) if usedKey == nil { return nil, errors.Wrap(errors.New("cannot find a key to decode the token"), errMessage) } if strings.HasPrefix(decodedHeader.Alg, "ES") { return jwx.DecodeAccessTokenECDSACustomClaims(accessToken, usedKey.X, usedKey.Y, usedKey.Crv, claims) } else if strings.HasPrefix(decodedHeader.Alg, "RS") { return jwx.DecodeAccessTokenRSACustomClaims(accessToken, usedKey.E, usedKey.N, claims) } return nil, fmt.Errorf("unsupported algorithm") } // DecodeAccessToken decodes the accessToken func (g *GoCloak) DecodeAccessToken(ctx context.Context, accessToken, realm string) (*jwt.Token, *jwt.MapClaims, error) { claims := jwt.MapClaims{} token, err := g.decodeAccessTokenWithClaims(ctx, accessToken, realm, claims) if err != nil { return nil, nil, err } return token, &claims, nil } // DecodeAccessTokenCustomClaims decodes the accessToken and writes claims into the given claims func (g *GoCloak) DecodeAccessTokenCustomClaims(ctx context.Context, accessToken, realm string, claims jwt.Claims) (*jwt.Token, error) { return g.decodeAccessTokenWithClaims(ctx, accessToken, realm, claims) } // GetToken uses TokenOptions to fetch a token. func (g *GoCloak) GetToken(ctx context.Context, realm string, options TokenOptions) (*JWT, error) { const errMessage = "could not get token" var token JWT var req *resty.Request if !NilOrEmpty(options.ClientSecret) { req = g.GetRequestWithBasicAuth(ctx, *options.ClientID, *options.ClientSecret) } else { req = g.GetRequest(ctx) } resp, err := req.SetFormData(options.FormData()). SetResult(&token). Post(g.getRealmURL(realm, g.Config.tokenEndpoint)) if err := checkForError(resp, err, errMessage); err != nil { return nil, err } return &token, nil } // GetRequestingPartyToken returns a requesting party token with permissions granted by the server func (g *GoCloak) GetRequestingPartyToken(ctx context.Context, token, realm string, options RequestingPartyTokenOptions) (*JWT, error) { const errMessage = "could not get requesting party token" var res JWT resp, err := g.getRequestingParty(ctx, token, realm, options, &res) if err := checkForError(resp, err, errMessage); err != nil { return nil, err } return &res, nil } // GetRequestingPartyPermissions returns a requesting party permissions granted by the server func (g *GoCloak) GetRequestingPartyPermissions(ctx context.Context, token, realm string, options RequestingPartyTokenOptions) (*[]RequestingPartyPermission, error) { const errMessage = "could not get requesting party token" var res []RequestingPartyPermission options.ResponseMode = StringP("permissions") resp, err := g.getRequestingParty(ctx, token, realm, options, &res) if err := checkForError(resp, err, errMessage); err != nil { return nil, err } return &res, nil } // GetRequestingPartyPermissionDecision returns a requesting party permission decision granted by the server func (g *GoCloak) GetRequestingPartyPermissionDecision(ctx context.Context, token, realm string, options RequestingPartyTokenOptions) (*RequestingPartyPermissionDecision, error) { const errMessage = "could not get requesting party token" var res RequestingPartyPermissionDecision options.ResponseMode = StringP("decision") resp, err := g.getRequestingParty(ctx, token, realm, options, &res) if err := checkForError(resp, err, errMessage); err != nil { return nil, err } return &res, nil } // RefreshToken refreshes the given token. // May return a *APIError with further details about the issue. func (g *GoCloak) RefreshToken(ctx context.Context, refreshToken, clientID, clientSecret, realm string) (*JWT, error) { return g.GetToken(ctx, realm, TokenOptions{ ClientID: &clientID, ClientSecret: &clientSecret, GrantType: StringP("refresh_token"), RefreshToken: &refreshToken, }) } // LoginAdmin performs a login with Admin client func (g *GoCloak) LoginAdmin(ctx context.Context, username, password, realm string) (*JWT, error) { return g.GetToken(ctx, realm, TokenOptions{ ClientID: StringP(adminClientID), GrantType: StringP("password"), Username: &username, Password: &password, }) } // LoginClient performs a login with client credentials func (g *GoCloak) LoginClient(ctx context.Context, clientID, clientSecret, realm string, scopes ...string) (*JWT, error) { opts := TokenOptions{ ClientID: &clientID, ClientSecret: &clientSecret, GrantType: StringP("client_credentials"), } if len(scopes) > 0 { opts.Scope = &scopes[0] } return g.GetToken(ctx, realm, opts) } // LoginClientTokenExchange will exchange the presented token for a user's token // Requires Token-Exchange is enabled: https://www.keycloak.org/docs/latest/securing_apps/index.html#_token-exchange func (g *GoCloak) LoginClientTokenExchange(ctx context.Context, clientID, token, clientSecret, realm, targetClient, userID string) (*JWT, error) { tokenOptions := TokenOptions{ ClientID: &clientID, ClientSecret: &clientSecret, GrantType: StringP("urn:ietf:params:oauth:grant-type:token-exchange"), SubjectToken: &token, RequestedTokenType: StringP("urn:ietf:params:oauth:token-type:refresh_token"), Audience: &targetClient, } if userID != "" { tokenOptions.RequestedSubject = &userID } return g.GetToken(ctx, realm, tokenOptions) } // LoginClientSignedJWT performs a login with client credentials and signed jwt claims func (g *GoCloak) LoginClientSignedJWT( ctx context.Context, clientID, realm string, key interface{}, signedMethod jwt.SigningMethod, expiresAt *jwt.NumericDate, ) (*JWT, error) { claims := jwt.RegisteredClaims{ ExpiresAt: expiresAt, Issuer: clientID, Subject: clientID, ID: ksuid.New().String(), Audience: jwt.ClaimStrings{ g.getRealmURL(realm), }, } assertion, err := jwx.SignClaims(claims, key, signedMethod) if err != nil { return nil, err } return g.GetToken(ctx, realm, TokenOptions{ ClientID: &clientID, GrantType: StringP("client_credentials"), ClientAssertionType: StringP("urn:ietf:params:oauth:client-assertion-type:jwt-bearer"), ClientAssertion: &assertion, }) } // Login performs a login with user credentials and a client func (g *GoCloak) Login(ctx context.Context, clientID, clientSecret, realm, username, password string) (*JWT, error) { return g.GetToken(ctx, realm, TokenOptions{ ClientID: &clientID, ClientSecret: &clientSecret, GrantType: StringP("password"), Username: &username, Password: &password, Scope: StringP("openid"), }) } // LoginOtp performs a login with user credentials and otp token func (g *GoCloak) LoginOtp(ctx context.Context, clientID, clientSecret, realm, username, password, totp string) (*JWT, error) { return g.GetToken(ctx, realm, TokenOptions{ ClientID: &clientID, ClientSecret: &clientSecret, GrantType: StringP("password"), Username: &username, Password: &password, Totp: &totp, }) } // Logout logs out users with refresh token func (g *GoCloak) Logout(ctx context.Context, clientID, clientSecret, realm, refreshToken string) error { const errMessage = "could not logout" resp, err := g.GetRequestWithBasicAuth(ctx, clientID, clientSecret). SetFormData(map[string]string{ "client_id": clientID, "refresh_token": refreshToken, }). Post(g.getRealmURL(realm, g.Config.logoutEndpoint)) return checkForError(resp, err, errMessage) } // LogoutPublicClient performs a logout using a public client and the accessToken. func (g *GoCloak) LogoutPublicClient(ctx context.Context, clientID, realm, accessToken, refreshToken string) error { const errMessage = "could not logout public client" resp, err := g.GetRequestWithBearerAuth(ctx, accessToken). SetFormData(map[string]string{ "client_id": clientID, "refresh_token": refreshToken, }). Post(g.getRealmURL(realm, g.Config.logoutEndpoint)) return checkForError(resp, err, errMessage) } // LogoutAllSessions logs out all sessions of a user given an id. func (g *GoCloak) LogoutAllSessions(ctx context.Context, accessToken, realm, userID string) error { const errMessage = "could not logout" resp, err := g.GetRequestWithBearerAuth(ctx, accessToken). Post(g.getAdminRealmURL(realm, "users", userID, "logout")) return checkForError(resp, err, errMessage) } // RevokeUserConsents revokes the given user consent. func (g *GoCloak) RevokeUserConsents(ctx context.Context, accessToken, realm, userID, clientID string) error { const errMessage = "could not revoke consents" resp, err := g.GetRequestWithBearerAuth(ctx, accessToken). Delete(g.getAdminRealmURL(realm, "users", userID, "consents", clientID)) return checkForError(resp, err, errMessage) } // LogoutUserSession logs out a single sessions of a user given a session id func (g *GoCloak) LogoutUserSession(ctx context.Context, accessToken, realm, session string) error { const errMessage = "could not logout" resp, err := g.GetRequestWithBearerAuth(ctx, accessToken). Delete(g.getAdminRealmURL(realm, "sessions", session)) return checkForError(resp, err, errMessage) } // ExecuteActionsEmail executes an actions email func (g *GoCloak) ExecuteActionsEmail(ctx context.Context, token, realm string, params ExecuteActionsEmail) error { const errMessage = "could not execute actions email" queryParams, err := GetQueryParams(params) if err != nil { return errors.Wrap(err, errMessage) } resp, err := g.GetRequestWithBearerAuth(ctx, token). SetBody(params.Actions). SetQueryParams(queryParams). Put(g.getAdminRealmURL(realm, "users", *(params.UserID), "execute-actions-email")) return checkForError(resp, err, errMessage) } // SendVerifyEmail sends a verification e-mail to a user. func (g *GoCloak) SendVerifyEmail(ctx context.Context, token, userID, realm string, params ...SendVerificationMailParams) error { const errMessage = "could not execute actions email" queryParams := map[string]string{} if params != nil { if params[0].ClientID != nil { queryParams["client_id"] = *params[0].ClientID } if params[0].RedirectURI != nil { queryParams["redirect_uri"] = *params[0].RedirectURI } } resp, err := g.GetRequestWithBearerAuth(ctx, token). SetQueryParams(queryParams). Put(g.getAdminRealmURL(realm, "users", userID, "send-verify-email")) return checkForError(resp, err, errMessage) } // CreateGroup creates a new group. func (g *GoCloak) CreateGroup(ctx context.Context, token, realm string, group Group) (string, error) { const errMessage = "could not create group" resp, err := g.GetRequestWithBearerAuth(ctx, token). SetBody(group). Post(g.getAdminRealmURL(realm, "groups")) if err := checkForError(resp, err, errMessage); err != nil { return "", err } return getID(resp), nil } // CreateChildGroup creates a new child group func (g *GoCloak) CreateChildGroup(ctx context.Context, token, realm, groupID string, group Group) (string, error) { const errMessage = "could not create child group" resp, err := g.GetRequestWithBearerAuth(ctx, token). SetBody(group). Post(g.getAdminRealmURL(realm, "groups", groupID, "children")) if err := checkForError(resp, err, errMessage); err != nil { return "", err } return getID(resp), nil } // CreateComponent creates the given component. func (g *GoCloak) CreateComponent(ctx context.Context, token, realm string, component Component) (string, error) { const errMessage = "could not create component" resp, err := g.GetRequestWithBearerAuth(ctx, token). SetBody(component). Post(g.getAdminRealmURL(realm, "components")) if err := checkForError(resp, err, errMessage); err != nil { return "", err } return getID(resp), nil } // CreateClient creates the given g. func (g *GoCloak) CreateClient(ctx context.Context, accessToken, realm string, newClient Client) (string, error) { const errMessage = "could not create client" resp, err := g.GetRequestWithBearerAuth(ctx, accessToken). SetBody(newClient). Post(g.getAdminRealmURL(realm, "clients")) if err := checkForError(resp, err, errMessage); err != nil { return "", err } return getID(resp), nil } // CreateClientRepresentation creates a new client representation func (g *GoCloak) CreateClientRepresentation(ctx context.Context, token, realm string, newClient Client) (*Client, error) { const errMessage = "could not create client representation" var result Client resp, err := g.GetRequestWithBearerAuth(ctx, token). SetResult(&result). SetBody(newClient). Post(g.getRealmURL(realm, "clients-registrations", "default")) if err := checkForError(resp, err, errMessage); err != nil { return nil, err } return &result, nil } // CreateClientRole creates a new role for a client func (g *GoCloak) CreateClientRole(ctx context.Context, token, realm, idOfClient string, role Role) (string, error) { const errMessage = "could not create client role" resp, err := g.GetRequestWithBearerAuth(ctx, token). SetBody(role). Post(g.getAdminRealmURL(realm, "clients", idOfClient, "roles")) if err := checkForError(resp, err, errMessage); err != nil { return "", err } return getID(resp), nil } // CreateClientScope creates a new client scope func (g *GoCloak) CreateClientScope(ctx context.Context, token, realm string, scope ClientScope) (string, error) { const errMessage = "could not create client scope" resp, err := g.GetRequestWithBearerAuth(ctx, token). SetBody(scope). Post(g.getAdminRealmURL(realm, "client-scopes")) if err := checkForError(resp, err, errMessage); err != nil { return "", err } return getID(resp), nil } // CreateClientScopeProtocolMapper creates a new protocolMapper under the given client scope func (g *GoCloak) CreateClientScopeProtocolMapper(ctx context.Context, token, realm, scopeID string, protocolMapper ProtocolMappers) (string, error) { const errMessage = "could not create client scope protocol mapper" resp, err := g.GetRequestWithBearerAuth(ctx, token). SetBody(protocolMapper). Post(g.getAdminRealmURL(realm, "client-scopes", scopeID, "protocol-mappers", "models")) if err := checkForError(resp, err, errMessage); err != nil { return "", err } return getID(resp), nil } // UpdateGroup updates the given group. func (g *GoCloak) UpdateGroup(ctx context.Context, token, realm string, updatedGroup Group) error { const errMessage = "could not update group" if NilOrEmpty(updatedGroup.ID) { return errors.Wrap(errors.New("ID of a group required"), errMessage) } resp, err := g.GetRequestWithBearerAuth(ctx, token). SetBody(updatedGroup). Put(g.getAdminRealmURL(realm, "groups", PString(updatedGroup.ID))) return checkForError(resp, err, errMessage) } // UpdateGroupManagementPermissions updates the given group management permissions func (g *GoCloak) UpdateGroupManagementPermissions(ctx context.Context, accessToken, realm string, idOfGroup string, managementPermissions ManagementPermissionRepresentation) (*ManagementPermissionRepresentation, error) { const errMessage = "could not update group management permissions" var result ManagementPermissionRepresentation resp, err := g.GetRequestWithBearerAuth(ctx, accessToken). SetResult(&result). SetBody(managementPermissions). Put(g.getAdminRealmURL(realm, "groups", idOfGroup, "management", "permissions")) if err := checkForError(resp, err, errMessage); err != nil { return nil, err } return &result, nil } // UpdateClient updates the given Client func (g *GoCloak) UpdateClient(ctx context.Context, token, realm string, updatedClient Client) error { const errMessage = "could not update client" if NilOrEmpty(updatedClient.ID) { return errors.Wrap(errors.New("ID of a client required"), errMessage) } resp, err := g.GetRequestWithBearerAuth(ctx, token). SetBody(updatedClient). Put(g.getAdminRealmURL(realm, "clients", PString(updatedClient.ID))) return checkForError(resp, err, errMessage) } // UpdateClientRepresentation updates the given client representation func (g *GoCloak) UpdateClientRepresentation(ctx context.Context, accessToken, realm string, updatedClient Client) (*Client, error) { const errMessage = "could not update client representation" if NilOrEmpty(updatedClient.ID) { return nil, errors.Wrap(errors.New("ID of a client required"), errMessage) } var result Client resp, err := g.GetRequestWithBearerAuth(ctx, accessToken). SetResult(&result). SetBody(updatedClient). Put(g.getRealmURL(realm, "clients-registrations", "default", PString(updatedClient.ClientID))) if err := checkForError(resp, err, errMessage); err != nil { return nil, err } return &result, nil } // UpdateClientManagementPermissions updates the given client management permissions func (g *GoCloak) UpdateClientManagementPermissions(ctx context.Context, accessToken, realm string, idOfClient string, managementPermissions ManagementPermissionRepresentation) (*ManagementPermissionRepresentation, error) { const errMessage = "could not update client management permissions" var result ManagementPermissionRepresentation resp, err := g.GetRequestWithBearerAuth(ctx, accessToken). SetResult(&result). SetBody(managementPermissions). Put(g.getAdminRealmURL(realm, "clients", idOfClient, "management", "permissions")) if err := checkForError(resp, err, errMessage); err != nil { return nil, err } return &result, nil } // UpdateRole updates the given role. func (g *GoCloak) UpdateRole(ctx context.Context, token, realm, idOfClient string, role Role) error { const errMessage = "could not update role" resp, err := g.GetRequestWithBearerAuth(ctx, token). SetBody(role). Put(g.getAdminRealmURL(realm, "clients", idOfClient, "roles", PString(role.Name))) return checkForError(resp, err, errMessage) } // UpdateClientScope updates the given client scope. func (g *GoCloak) UpdateClientScope(ctx context.Context, token, realm string, scope ClientScope) error { const errMessage = "could not update client scope" resp, err := g.GetRequestWithBearerAuth(ctx, token). SetBody(scope). Put(g.getAdminRealmURL(realm, "client-scopes", PString(scope.ID))) return checkForError(resp, err, errMessage) } // UpdateClientScopeProtocolMapper updates the given protocol mapper for a client scope func (g *GoCloak) UpdateClientScopeProtocolMapper(ctx context.Context, token, realm, scopeID string, protocolMapper ProtocolMappers) error { const errMessage = "could not update client scope" resp, err := g.GetRequestWithBearerAuth(ctx, token). SetBody(protocolMapper). Put(g.getAdminRealmURL(realm, "client-scopes", scopeID, "protocol-mappers", "models", PString(protocolMapper.ID))) return checkForError(resp, err, errMessage) } // DeleteGroup deletes the group with the given groupID. func (g *GoCloak) DeleteGroup(ctx context.Context, token, realm, groupID string) error { const errMessage = "could not delete group" resp, err := g.GetRequestWithBearerAuth(ctx, token). Delete(g.getAdminRealmURL(realm, "groups", groupID)) return checkForError(resp, err, errMessage) } // DeleteClient deletes a given client func (g *GoCloak) DeleteClient(ctx context.Context, token, realm, idOfClient string) error { const errMessage = "could not delete client" resp, err := g.GetRequestWithBearerAuth(ctx, token). Delete(g.getAdminRealmURL(realm, "clients", idOfClient)) return checkForError(resp, err, errMessage) } // DeleteComponent deletes the component with the given id. func (g *GoCloak) DeleteComponent(ctx context.Context, token, realm, componentID string) error { const errMessage = "could not delete component" resp, err := g.GetRequestWithBearerAuth(ctx, token). Delete(g.getAdminRealmURL(realm, "components", componentID)) return checkForError(resp, err, errMessage) } // DeleteClientRepresentation deletes a given client representation. func (g *GoCloak) DeleteClientRepresentation(ctx context.Context, accessToken, realm, clientID string) error { const errMessage = "could not delete client representation" resp, err := g.GetRequestWithBearerAuth(ctx, accessToken). Delete(g.getRealmURL(realm, "clients-registrations", "default", clientID)) return checkForError(resp, err, errMessage) } // DeleteClientRole deletes a given role. func (g *GoCloak) DeleteClientRole(ctx context.Context, token, realm, idOfClient, roleName string) error { const errMessage = "could not delete client role" resp, err := g.GetRequestWithBearerAuth(ctx, token). Delete(g.getAdminRealmURL(realm, "clients", idOfClient, "roles", roleName)) return checkForError(resp, err, errMessage) } // DeleteClientScope deletes the scope with the given id. func (g *GoCloak) DeleteClientScope(ctx context.Context, token, realm, scopeID string) error { const errMessage = "could not delete client scope" resp, err := g.GetRequestWithBearerAuth(ctx, token). Delete(g.getAdminRealmURL(realm, "client-scopes", scopeID)) return checkForError(resp, err, errMessage) } // DeleteClientScopeProtocolMapper deletes the given protocol mapper from the client scope func (g *GoCloak) DeleteClientScopeProtocolMapper(ctx context.Context, token, realm, scopeID, protocolMapperID string) error { const errMessage = "could not delete client scope" resp, err := g.GetRequestWithBearerAuth(ctx, token). Delete(g.getAdminRealmURL(realm, "client-scopes", scopeID, "protocol-mappers", "models", protocolMapperID)) return checkForError(resp, err, errMessage) } // GetClient returns a client func (g *GoCloak) GetClient(ctx context.Context, token, realm, idOfClient string) (*Client, error) { const errMessage = "could not get client" var result Client resp, err := g.GetRequestWithBearerAuth(ctx, token). SetResult(&result). Get(g.getAdminRealmURL(realm, "clients", idOfClient)) if err := checkForError(resp, err, errMessage); err != nil { return nil, err } return &result, nil } // GetClientRepresentation returns a client representation func (g *GoCloak) GetClientRepresentation(ctx context.Context, accessToken, realm, clientID string) (*Client, error) { const errMessage = "could not get client representation" var result Client resp, err := g.GetRequestWithBearerAuth(ctx, accessToken). SetResult(&result). Get(g.getRealmURL(realm, "clients-registrations", "default", clientID)) if err := checkForError(resp, err, errMessage); err != nil { return nil, err } return &result, nil } // GetAdapterConfiguration returns a adapter configuration func (g *GoCloak) GetAdapterConfiguration(ctx context.Context, accessToken, realm, clientID string) (*AdapterConfiguration, error) { const errMessage = "could not get adapter configuration" var result AdapterConfiguration resp, err := g.GetRequestWithBearerAuth(ctx, accessToken). SetResult(&result). Get(g.getRealmURL(realm, "clients-registrations", "install", clientID)) if err := checkForError(resp, err, errMessage); err != nil { return nil, err } return &result, nil } // GetClientsDefaultScopes returns a list of the client's default scopes func (g *GoCloak) GetClientsDefaultScopes(ctx context.Context, token, realm, idOfClient string) ([]*ClientScope, error) { const errMessage = "could not get clients default scopes" var result []*ClientScope resp, err := g.GetRequestWithBearerAuth(ctx, token). SetResult(&result). Get(g.getAdminRealmURL(realm, "clients", idOfClient, "default-client-scopes")) if err := checkForError(resp, err, errMessage); err != nil { return nil, err } return result, nil } // AddDefaultScopeToClient adds a client scope to the list of client's default scopes func (g *GoCloak) AddDefaultScopeToClient(ctx context.Context, token, realm, idOfClient, scopeID string) error { const errMessage = "could not add default scope to client" resp, err := g.GetRequestWithBearerAuth(ctx, token). Put(g.getAdminRealmURL(realm, "clients", idOfClient, "default-client-scopes", scopeID)) return checkForError(resp, err, errMessage) } // RemoveDefaultScopeFromClient removes a client scope from the list of client's default scopes func (g *GoCloak) RemoveDefaultScopeFromClient(ctx context.Context, token, realm, idOfClient, scopeID string) error { const errMessage = "could not remove default scope from client" resp, err := g.GetRequestWithBearerAuth(ctx, token). Delete(g.getAdminRealmURL(realm, "clients", idOfClient, "default-client-scopes", scopeID)) return checkForError(resp, err, errMessage) } // GetClientsOptionalScopes returns a list of the client's optional scopes func (g *GoCloak) GetClientsOptionalScopes(ctx context.Context, token, realm, idOfClient string) ([]*ClientScope, error) { const errMessage = "could not get clients optional scopes" var result []*ClientScope resp, err := g.GetRequestWithBearerAuth(ctx, token). SetResult(&result). Get(g.getAdminRealmURL(realm, "clients", idOfClient, "optional-client-scopes")) if err := checkForError(resp, err, errMessage); err != nil { return nil, err } return result, nil } // AddOptionalScopeToClient adds a client scope to the list of client's optional scopes func (g *GoCloak) AddOptionalScopeToClient(ctx context.Context, token, realm, idOfClient, scopeID string) error { const errMessage = "could not add optional scope to client" resp, err := g.GetRequestWithBearerAuth(ctx, token). Put(g.getAdminRealmURL(realm, "clients", idOfClient, "optional-client-scopes", scopeID)) return checkForError(resp, err, errMessage) } // RemoveOptionalScopeFromClient deletes a client scope from the list of client's optional scopes func (g *GoCloak) RemoveOptionalScopeFromClient(ctx context.Context, token, realm, idOfClient, scopeID string) error { const errMessage = "could not remove optional scope from client" resp, err := g.GetRequestWithBearerAuth(ctx, token). Delete(g.getAdminRealmURL(realm, "clients", idOfClient, "optional-client-scopes", scopeID)) return checkForError(resp, err, errMessage) } // GetDefaultOptionalClientScopes returns a list of default realm optional scopes func (g *GoCloak) GetDefaultOptionalClientScopes(ctx context.Context, token, realm string) ([]*ClientScope, error) { const errMessage = "could not get default optional client scopes" var result []*ClientScope resp, err := g.GetRequestWithBearerAuth(ctx, token). SetResult(&result). Get(g.getAdminRealmURL(realm, "default-optional-client-scopes")) if err := checkForError(resp, err, errMessage); err != nil { return nil, err } return result, nil } // GetDefaultDefaultClientScopes returns a list of default realm default scopes func (g *GoCloak) GetDefaultDefaultClientScopes(ctx context.Context, token, realm string) ([]*ClientScope, error) { const errMessage = "could not get default client scopes" var result []*ClientScope resp, err := g.GetRequestWithBearerAuth(ctx, token). SetResult(&result). Get(g.getAdminRealmURL(realm, "default-default-client-scopes")) if err := checkForError(resp, err, errMessage); err != nil { return nil, err } return result, nil } // GetClientScope returns a clientscope func (g *GoCloak) GetClientScope(ctx context.Context, token, realm, scopeID string) (*ClientScope, error) { const errMessage = "could not get client scope" var result ClientScope resp, err := g.GetRequestWithBearerAuth(ctx, token). SetResult(&result). Get(g.getAdminRealmURL(realm, "client-scopes", scopeID)) if err := checkForError(resp, err, errMessage); err != nil { return nil, err } return &result, nil } // GetClientScopes returns all client scopes func (g *GoCloak) GetClientScopes(ctx context.Context, token, realm string) ([]*ClientScope, error) { const errMessage = "could not get client scopes" var result []*ClientScope resp, err := g.GetRequestWithBearerAuth(ctx, token). SetResult(&result). Get(g.getAdminRealmURL(realm, "client-scopes")) if err := checkForError(resp, err, errMessage); err != nil { return nil, err } return result, nil } // GetClientScopeProtocolMappers returns all protocol mappers of a client scope func (g *GoCloak) GetClientScopeProtocolMappers(ctx context.Context, token, realm, scopeID string) ([]*ProtocolMappers, error) { const errMessage = "could not get client scope protocol mappers" var result []*ProtocolMappers resp, err := g.GetRequestWithBearerAuth(ctx, token). SetResult(&result). Get(g.getAdminRealmURL(realm, "client-scopes", scopeID, "protocol-mappers", "models")) if err := checkForError(resp, err, errMessage); err != nil { return nil, err } return result, nil } // GetClientScopeProtocolMapper returns a protocol mapper of a client scope func (g *GoCloak) GetClientScopeProtocolMapper(ctx context.Context, token, realm, scopeID, protocolMapperID string) (*ProtocolMappers, error) { const errMessage = "could not get client scope protocol mappers" var result *ProtocolMappers resp, err := g.GetRequestWithBearerAuth(ctx, token). SetResult(&result). Get(g.getAdminRealmURL(realm, "client-scopes", scopeID, "protocol-mappers", "models", protocolMapperID)) if err := checkForError(resp, err, errMessage); err != nil { return nil, err } return result, nil } // GetClientScopeMappings returns all scope mappings for the client func (g *GoCloak) GetClientScopeMappings(ctx context.Context, token, realm, idOfClient string) (*MappingsRepresentation, error) { const errMessage = "could not get all scope mappings for the client" var result *MappingsRepresentation resp, err := g.GetRequestWithBearerAuth(ctx, token). SetResult(&result). Get(g.getAdminRealmURL(realm, "clients", idOfClient, "scope-mappings")) if err := checkForError(resp, err, errMessage); err != nil { return nil, err } return result, nil } // GetClientScopeMappingsRealmRoles returns realm-level roles associated with the client’s scope func (g *GoCloak) GetClientScopeMappingsRealmRoles(ctx context.Context, token, realm, idOfClient string) ([]*Role, error) { const errMessage = "could not get realm-level roles with the client’s scope" var result []*Role resp, err := g.GetRequestWithBearerAuth(ctx, token). SetResult(&result). Get(g.getAdminRealmURL(realm, "clients", idOfClient, "scope-mappings", "realm")) if err := checkForError(resp, err, errMessage); err != nil { return nil, err } return result, nil } // GetClientScopeMappingsRealmRolesAvailable returns realm-level roles that are available to attach to this client’s scope func (g *GoCloak) GetClientScopeMappingsRealmRolesAvailable(ctx context.Context, token, realm, idOfClient string) ([]*Role, error) { const errMessage = "could not get available realm-level roles with the client’s scope" var result []*Role resp, err := g.GetRequestWithBearerAuth(ctx, token). SetResult(&result). Get(g.getAdminRealmURL(realm, "clients", idOfClient, "scope-mappings", "realm", "available")) if err := checkForError(resp, err, errMessage); err != nil { return nil, err } return result, nil } // CreateClientScopeMappingsRealmRoles create realm-level roles to the client’s scope func (g *GoCloak) CreateClientScopeMappingsRealmRoles(ctx context.Context, token, realm, idOfClient string, roles []Role) error { const errMessage = "could not create realm-level roles to the client’s scope" resp, err := g.GetRequestWithBearerAuth(ctx, token). SetBody(roles). Post(g.getAdminRealmURL(realm, "clients", idOfClient, "scope-mappings", "realm")) return checkForError(resp, err, errMessage) } // DeleteClientScopeMappingsRealmRoles deletes realm-level roles from the client’s scope func (g *GoCloak) DeleteClientScopeMappingsRealmRoles(ctx context.Context, token, realm, idOfClient string, roles []Role) error { const errMessage = "could not delete realm-level roles from the client’s scope" resp, err := g.GetRequestWithBearerAuth(ctx, token). SetBody(roles). Delete(g.getAdminRealmURL(realm, "clients", idOfClient, "scope-mappings", "realm")) return checkForError(resp, err, errMessage) } // GetClientScopeMappingsClientRoles returns roles associated with a client’s scope func (g *GoCloak) GetClientScopeMappingsClientRoles(ctx context.Context, token, realm, idOfClient, idOfSelectedClient string) ([]*Role, error) { const errMessage = "could not get roles associated with a client’s scope" var result []*Role resp, err := g.GetRequestWithBearerAuth(ctx, token). SetResult(&result). Get(g.getAdminRealmURL(realm, "clients", idOfClient, "scope-mappings", "clients", idOfSelectedClient)) if err := checkForError(resp, err, errMessage); err != nil { return nil, err } return result, nil } // GetClientScopeMappingsClientRolesAvailable returns available roles associated with a client’s scope func (g *GoCloak) GetClientScopeMappingsClientRolesAvailable(ctx context.Context, token, realm, idOfClient, idOfSelectedClient string) ([]*Role, error) { const errMessage = "could not get available roles associated with a client’s scope" var result []*Role resp, err := g.GetRequestWithBearerAuth(ctx, token). SetResult(&result). Get(g.getAdminRealmURL(realm, "clients", idOfClient, "scope-mappings", "clients", idOfSelectedClient, "available")) if err := checkForError(resp, err, errMessage); err != nil { return nil, err } return result, nil } // CreateClientScopeMappingsClientRoles creates client-level roles from the client’s scope func (g *GoCloak) CreateClientScopeMappingsClientRoles(ctx context.Context, token, realm, idOfClient, idOfSelectedClient string, roles []Role) error { const errMessage = "could not create client-level roles from the client’s scope" resp, err := g.GetRequestWithBearerAuth(ctx, token). SetBody(roles). Post(g.getAdminRealmURL(realm, "clients", idOfClient, "scope-mappings", "clients", idOfSelectedClient)) return checkForError(resp, err, errMessage) } // DeleteClientScopeMappingsClientRoles deletes client-level roles from the client’s scope func (g *GoCloak) DeleteClientScopeMappingsClientRoles(ctx context.Context, token, realm, idOfClient, idOfSelectedClient string, roles []Role) error { const errMessage = "could not delete client-level roles from the client’s scope" resp, err := g.GetRequestWithBearerAuth(ctx, token). SetBody(roles). Delete(g.getAdminRealmURL(realm, "clients", idOfClient, "scope-mappings", "clients", idOfSelectedClient)) return checkForError(resp, err, errMessage) } // GetClientSecret returns a client's secret func (g *GoCloak) GetClientSecret(ctx context.Context, token, realm, idOfClient string) (*CredentialRepresentation, error) { const errMessage = "could not get client secret" var result CredentialRepresentation resp, err := g.GetRequestWithBearerAuth(ctx, token). SetResult(&result). Get(g.getAdminRealmURL(realm, "clients", idOfClient, "client-secret")) if err := checkForError(resp, err, errMessage); err != nil { return nil, err } return &result, nil } // GetClientServiceAccount retrieves the service account "user" for a client if enabled func (g *GoCloak) GetClientServiceAccount(ctx context.Context, token, realm, idOfClient string) (*User, error) { const errMessage = "could not get client service account" var result User resp, err := g.GetRequestWithBearerAuth(ctx, token). SetResult(&result). Get(g.getAdminRealmURL(realm, "clients", idOfClient, "service-account-user")) if err := checkForError(resp, err, errMessage); err != nil { return nil, err } return &result, nil } // RegenerateClientSecret triggers the creation of the new client secret. func (g *GoCloak) RegenerateClientSecret(ctx context.Context, token, realm, idOfClient string) (*CredentialRepresentation, error) { const errMessage = "could not regenerate client secret" var result CredentialRepresentation resp, err := g.GetRequestWithBearerAuth(ctx, token). SetResult(&result). Post(g.getAdminRealmURL(realm, "clients", idOfClient, "client-secret")) if err := checkForError(resp, err, errMessage); err != nil { return nil, err } return &result, nil } // GetClientOfflineSessions returns offline sessions associated with the client func (g *GoCloak) GetClientOfflineSessions(ctx context.Context, token, realm, idOfClient string, params ...GetClientUserSessionsParams) ([]*UserSessionRepresentation, error) { const errMessage = "could not get client offline sessions" var res []*UserSessionRepresentation queryParams := map[string]string{} if len(params) > 0 { var err error queryParams, err = GetQueryParams(params[0]) if err != nil { return nil, errors.Wrap(err, errMessage) } } resp, err := g.GetRequestWithBearerAuth(ctx, token). SetResult(&res). SetQueryParams(queryParams). Get(g.getAdminRealmURL(realm, "clients", idOfClient, "offline-sessions")) if err := checkForError(resp, err, errMessage); err != nil { return nil, err } return res, nil } // GetClientUserSessions returns user sessions associated with the client func (g *GoCloak) GetClientUserSessions(ctx context.Context, token, realm, idOfClient string, params ...GetClientUserSessionsParams) ([]*UserSessionRepresentation, error) { const errMessage = "could not get client user sessions" var res []*UserSessionRepresentation queryParams := map[string]string{} if len(params) > 0 { var err error queryParams, err = GetQueryParams(params[0]) if err != nil { return nil, errors.Wrap(err, errMessage) } } resp, err := g.GetRequestWithBearerAuth(ctx, token). SetResult(&res). SetQueryParams(queryParams). Get(g.getAdminRealmURL(realm, "clients", idOfClient, "user-sessions")) if err := checkForError(resp, err, errMessage); err != nil { return nil, err } return res, nil } // CreateClientProtocolMapper creates a protocol mapper in client scope func (g *GoCloak) CreateClientProtocolMapper(ctx context.Context, token, realm, idOfClient string, mapper ProtocolMapperRepresentation) (string, error) { const errMessage = "could not create client protocol mapper" resp, err := g.GetRequestWithBearerAuth(ctx, token). SetBody(mapper). Post(g.getAdminRealmURL(realm, "clients", idOfClient, "protocol-mappers", "models")) if err := checkForError(resp, err, errMessage); err != nil { return "", err } return getID(resp), nil } // UpdateClientProtocolMapper updates a protocol mapper in client scope func (g *GoCloak) UpdateClientProtocolMapper(ctx context.Context, token, realm, idOfClient, mapperID string, mapper ProtocolMapperRepresentation) error { const errMessage = "could not update client protocol mapper" resp, err := g.GetRequestWithBearerAuth(ctx, token). SetBody(mapper). Put(g.getAdminRealmURL(realm, "clients", idOfClient, "protocol-mappers", "models", mapperID)) return checkForError(resp, err, errMessage) } // DeleteClientProtocolMapper deletes a protocol mapper in client scope func (g *GoCloak) DeleteClientProtocolMapper(ctx context.Context, token, realm, idOfClient, mapperID string) error { const errMessage = "could not delete client protocol mapper" resp, err := g.GetRequestWithBearerAuth(ctx, token). Delete(g.getAdminRealmURL(realm, "clients", idOfClient, "protocol-mappers", "models", mapperID)) return checkForError(resp, err, errMessage) } // GetKeyStoreConfig get keystoreconfig of the realm func (g *GoCloak) GetKeyStoreConfig(ctx context.Context, token, realm string) (*KeyStoreConfig, error) { const errMessage = "could not get key store config" var result KeyStoreConfig resp, err := g.GetRequestWithBearerAuth(ctx, token). SetResult(&result). Get(g.getAdminRealmURL(realm, "keys")) if err := checkForError(resp, err, errMessage); err != nil { return nil, err } return &result, nil } // GetComponents get all components in realm func (g *GoCloak) GetComponents(ctx context.Context, token, realm string) ([]*Component, error) { const errMessage = "could not get components" var result []*Component resp, err := g.GetRequestWithBearerAuth(ctx, token). SetResult(&result). Get(g.getAdminRealmURL(realm, "components")) if err := checkForError(resp, err, errMessage); err != nil { return nil, err } return result, nil } // GetComponentsWithParams get all components in realm with query params func (g *GoCloak) GetComponentsWithParams(ctx context.Context, token, realm string, params GetComponentsParams) ([]*Component, error) { const errMessage = "could not get components" var result []*Component queryParams, err := GetQueryParams(params) if err != nil { return nil, errors.Wrap(err, errMessage) } resp, err := g.GetRequestWithBearerAuth(ctx, token). SetResult(&result). SetQueryParams(queryParams). Get(g.getAdminRealmURL(realm, "components")) if err := checkForError(resp, err, errMessage); err != nil { return nil, err } return result, nil } // GetComponent get exactly one component by ID func (g *GoCloak) GetComponent(ctx context.Context, token, realm string, componentID string) (*Component, error) { const errMessage = "could not get components" var result *Component componentURL := fmt.Sprintf("components/%s", componentID) resp, err := g.GetRequestWithBearerAuth(ctx, token). SetResult(&result). Get(g.getAdminRealmURL(realm, componentURL)) if err := checkForError(resp, err, errMessage); err != nil { return nil, err } return result, nil } // UpdateComponent updates the given component func (g *GoCloak) UpdateComponent(ctx context.Context, token, realm string, component Component) error { const errMessage = "could not update component" resp, err := g.GetRequestWithBearerAuth(ctx, token). SetBody(component). Put(g.getAdminRealmURL(realm, "components", PString(component.ID))) return checkForError(resp, err, errMessage) } // GetDefaultGroups returns a list of default groups func (g *GoCloak) GetDefaultGroups(ctx context.Context, token, realm string) ([]*Group, error) { const errMessage = "could not get default groups" var result []*Group resp, err := g.GetRequestWithBearerAuth(ctx, token). SetResult(&result). Get(g.getAdminRealmURL(realm, "default-groups")) if err := checkForError(resp, err, errMessage); err != nil { return nil, err } return result, nil } // AddDefaultGroup adds group to the list of default groups func (g *GoCloak) AddDefaultGroup(ctx context.Context, token, realm, groupID string) error { const errMessage = "could not add default group" resp, err := g.GetRequestWithBearerAuth(ctx, token). Put(g.getAdminRealmURL(realm, "default-groups", groupID)) return checkForError(resp, err, errMessage) } // RemoveDefaultGroup removes group from the list of default groups func (g *GoCloak) RemoveDefaultGroup(ctx context.Context, token, realm, groupID string) error { const errMessage = "could not remove default group" resp, err := g.GetRequestWithBearerAuth(ctx, token). Delete(g.getAdminRealmURL(realm, "default-groups", groupID)) return checkForError(resp, err, errMessage) } func (g *GoCloak) getRoleMappings(ctx context.Context, token, realm, path, objectID string) (*MappingsRepresentation, error) { const errMessage = "could not get role mappings" var result MappingsRepresentation resp, err := g.GetRequestWithBearerAuth(ctx, token). SetResult(&result). Get(g.getAdminRealmURL(realm, path, objectID, "role-mappings")) if err := checkForError(resp, err, errMessage); err != nil { return nil, err } return &result, nil } // GetRoleMappingByGroupID gets the role mappings by group func (g *GoCloak) GetRoleMappingByGroupID(ctx context.Context, token, realm, groupID string) (*MappingsRepresentation, error) { return g.getRoleMappings(ctx, token, realm, "groups", groupID) } // GetRoleMappingByUserID gets the role mappings by user func (g *GoCloak) GetRoleMappingByUserID(ctx context.Context, token, realm, userID string) (*MappingsRepresentation, error) { return g.getRoleMappings(ctx, token, realm, "users", userID) } // GetGroup get group with id in realm func (g *GoCloak) GetGroup(ctx context.Context, token, realm, groupID string) (*Group, error) { const errMessage = "could not get group" var result Group resp, err := g.GetRequestWithBearerAuth(ctx, token). SetResult(&result). Get(g.getAdminRealmURL(realm, "groups", groupID)) if err := checkForError(resp, err, errMessage); err != nil { return nil, err } return &result, nil } // GetGroupByPath get group with path in realm func (g *GoCloak) GetGroupByPath(ctx context.Context, token, realm, groupPath string) (*Group, error) { const errMessage = "could not get group" var result Group resp, err := g.GetRequestWithBearerAuth(ctx, token). SetResult(&result). Get(g.getAdminRealmURL(realm, "group-by-path", groupPath)) if err := checkForError(resp, err, errMessage); err != nil { return nil, err } return &result, nil } // GetGroups get all groups in realm func (g *GoCloak) GetGroups(ctx context.Context, token, realm string, params GetGroupsParams) ([]*Group, error) { const errMessage = "could not get groups" var result []*Group queryParams, err := GetQueryParams(params) if err != nil { return nil, errors.Wrap(err, errMessage) } resp, err := g.GetRequestWithBearerAuth(ctx, token). SetResult(&result). SetQueryParams(queryParams). Get(g.getAdminRealmURL(realm, "groups")) if err := checkForError(resp, err, errMessage); err != nil { return nil, err } return result, nil } // GetGroupManagementPermissions returns whether group Authorization permissions have been initialized or not and a reference // to the managed permissions func (g *GoCloak) GetGroupManagementPermissions(ctx context.Context, token, realm string, idOfGroup string) (*ManagementPermissionRepresentation, error) { const errMessage = "could not get management permissions" var result ManagementPermissionRepresentation resp, err := g.GetRequestWithBearerAuth(ctx, token). SetResult(&result). Get(g.getAdminRealmURL(realm, "groups", idOfGroup, "management", "permissions")) if err := checkForError(resp, err, errMessage); err != nil { return nil, err } return &result, nil } // GetGroupsByRole gets groups assigned with a specific role of a realm func (g *GoCloak) GetGroupsByRole(ctx context.Context, token, realm string, roleName string) ([]*Group, error) { const errMessage = "could not get groups" var result []*Group resp, err := g.GetRequestWithBearerAuth(ctx, token). SetResult(&result). Get(g.getAdminRealmURL(realm, "roles", roleName, "groups")) if err := checkForError(resp, err, errMessage); err != nil { return nil, err } return result, nil } // GetGroupsByClientRole gets groups with specified roles assigned of given client within a realm func (g *GoCloak) GetGroupsByClientRole(ctx context.Context, token, realm string, roleName string, clientID string) ([]*Group, error) { const errMessage = "could not get groups" var result []*Group resp, err := g.GetRequestWithBearerAuth(ctx, token). SetResult(&result). Get(g.getAdminRealmURL(realm, "clients", clientID, "roles", roleName, "groups")) if err := checkForError(resp, err, errMessage); err != nil { return nil, err } return result, nil } // GetGroupsCount gets the groups count in the realm func (g *GoCloak) GetGroupsCount(ctx context.Context, token, realm string, params GetGroupsParams) (int, error) { const errMessage = "could not get groups count" var result GroupsCount queryParams, err := GetQueryParams(params) if err != nil { return 0, errors.Wrap(err, errMessage) } resp, err := g.GetRequestWithBearerAuth(ctx, token). SetResult(&result). SetQueryParams(queryParams). Get(g.getAdminRealmURL(realm, "groups", "count")) if err := checkForError(resp, err, errMessage); err != nil { return -1, errors.Wrap(err, errMessage) } return result.Count, nil } // GetGroupMembers get a list of users of group with id in realm func (g *GoCloak) GetGroupMembers(ctx context.Context, token, realm, groupID string, params GetGroupsParams) ([]*User, error) { const errMessage = "could not get group members" var result []*User queryParams, err := GetQueryParams(params) if err != nil { return nil, errors.Wrap(err, errMessage) } resp, err := g.GetRequestWithBearerAuth(ctx, token). SetResult(&result). SetQueryParams(queryParams). Get(g.getAdminRealmURL(realm, "groups", groupID, "members")) if err := checkForError(resp, err, errMessage); err != nil { return nil, err } return result, nil } // GetClientRoles get all roles for the given client in realm func (g *GoCloak) GetClientRoles(ctx context.Context, token, realm, idOfClient string, params GetRoleParams) ([]*Role, error) { const errMessage = "could not get client roles" var result []*Role queryParams, err := GetQueryParams(params) if err != nil { return nil, errors.Wrap(err, errMessage) } resp, err := g.GetRequestWithBearerAuth(ctx, token). SetResult(&result). SetQueryParams(queryParams). Get(g.getAdminRealmURL(realm, "clients", idOfClient, "roles")) if err := checkForError(resp, err, errMessage); err != nil { return nil, err } return result, nil } // GetClientRoleByID gets role for the given client in realm using role ID func (g *GoCloak) GetClientRoleByID(ctx context.Context, token, realm, roleID string) (*Role, error) { const errMessage = "could not get client role" var result Role resp, err := g.GetRequestWithBearerAuth(ctx, token). SetResult(&result). Get(g.getAdminRealmURL(realm, "roles-by-id", roleID)) if err := checkForError(resp, err, errMessage); err != nil { return nil, err } return &result, nil } // GetClientRolesByUserID returns all client roles assigned to the given user func (g *GoCloak) GetClientRolesByUserID(ctx context.Context, token, realm, idOfClient, userID string) ([]*Role, error) { const errMessage = "could not client roles by user id" var result []*Role resp, err := g.GetRequestWithBearerAuth(ctx, token). SetResult(&result). Get(g.getAdminRealmURL(realm, "users", userID, "role-mappings", "clients", idOfClient)) if err = checkForError(resp, err, errMessage); err != nil { return nil, err } return result, nil } // GetClientRolesByGroupID returns all client roles assigned to the given group func (g *GoCloak) GetClientRolesByGroupID(ctx context.Context, token, realm, idOfClient, groupID string) ([]*Role, error) { const errMessage = "could not get client roles by group id" var result []*Role resp, err := g.GetRequestWithBearerAuth(ctx, token). SetResult(&result). Get(g.getAdminRealmURL(realm, "groups", groupID, "role-mappings", "clients", idOfClient)) if err = checkForError(resp, err, errMessage); err != nil { return nil, err } return result, nil } // GetCompositeClientRolesByRoleID returns all client composite roles associated with the given client role func (g *GoCloak) GetCompositeClientRolesByRoleID(ctx context.Context, token, realm, idOfClient, roleID string) ([]*Role, error) { const errMessage = "could not get composite client roles by role id" var result []*Role resp, err := g.GetRequestWithBearerAuth(ctx, token). SetResult(&result). Get(g.getAdminRealmURL(realm, "roles-by-id", roleID, "composites", "clients", idOfClient)) if err = checkForError(resp, err, errMessage); err != nil { return nil, err } return result, nil } // GetCompositeClientRolesByUserID returns all client roles and composite roles assigned to the given user func (g *GoCloak) GetCompositeClientRolesByUserID(ctx context.Context, token, realm, idOfClient, userID string) ([]*Role, error) { const errMessage = "could not get composite client roles by user id" var result []*Role resp, err := g.GetRequestWithBearerAuth(ctx, token). SetResult(&result). Get(g.getAdminRealmURL(realm, "users", userID, "role-mappings", "clients", idOfClient, "composite")) if err = checkForError(resp, err, errMessage); err != nil { return nil, err } return result, nil } // GetAvailableClientRolesByUserID returns all available client roles to the given user func (g *GoCloak) GetAvailableClientRolesByUserID(ctx context.Context, token, realm, idOfClient, userID string) ([]*Role, error) { const errMessage = "could not get available client roles by user id" var result []*Role resp, err := g.GetRequestWithBearerAuth(ctx, token). SetResult(&result). Get(g.getAdminRealmURL(realm, "users", userID, "role-mappings", "clients", idOfClient, "available")) if err = checkForError(resp, err, errMessage); err != nil { return nil, err } return result, nil } // GetAvailableClientRolesByGroupID returns all available roles to the given group func (g *GoCloak) GetAvailableClientRolesByGroupID(ctx context.Context, token, realm, idOfClient, groupID string) ([]*Role, error) { const errMessage = "could not get available client roles by user id" var result []*Role resp, err := g.GetRequestWithBearerAuth(ctx, token). SetResult(&result). Get(g.getAdminRealmURL(realm, "groups", groupID, "role-mappings", "clients", idOfClient, "available")) if err = checkForError(resp, err, errMessage); err != nil { return nil, err } return result, nil } // GetCompositeClientRolesByGroupID returns all client roles and composite roles assigned to the given group func (g *GoCloak) GetCompositeClientRolesByGroupID(ctx context.Context, token, realm, idOfClient, groupID string) ([]*Role, error) { const errMessage = "could not get composite client roles by group id" var result []*Role resp, err := g.GetRequestWithBearerAuth(ctx, token). SetResult(&result). Get(g.getAdminRealmURL(realm, "groups", groupID, "role-mappings", "clients", idOfClient, "composite")) if err = checkForError(resp, err, errMessage); err != nil { return nil, err } return result, nil } // GetClientRole get a role for the given client in a realm by role name func (g *GoCloak) GetClientRole(ctx context.Context, token, realm, idOfClient, roleName string) (*Role, error) { const errMessage = "could not get client role" var result Role resp, err := g.GetRequestWithBearerAuth(ctx, token). SetResult(&result). Get(g.getAdminRealmURL(realm, "clients", idOfClient, "roles", roleName)) if err := checkForError(resp, err, errMessage); err != nil { return nil, err } return &result, nil } // GetClients gets all clients in realm func (g *GoCloak) GetClients(ctx context.Context, token, realm string, params GetClientsParams) ([]*Client, error) { const errMessage = "could not get clients" var result []*Client queryParams, err := GetQueryParams(params) if err != nil { return nil, errors.Wrap(err, errMessage) } resp, err := g.GetRequestWithBearerAuth(ctx, token). SetResult(&result). SetQueryParams(queryParams). Get(g.getAdminRealmURL(realm, "clients")) if err := checkForError(resp, err, errMessage); err != nil { return nil, err } return result, nil } // GetClientManagementPermissions returns whether client Authorization permissions have been initialized or not and a reference // to the managed permissions func (g *GoCloak) GetClientManagementPermissions(ctx context.Context, token, realm string, idOfClient string) (*ManagementPermissionRepresentation, error) { const errMessage = "could not get management permissions" var result ManagementPermissionRepresentation resp, err := g.GetRequestWithBearerAuth(ctx, token). SetResult(&result). Get(g.getAdminRealmURL(realm, "clients", idOfClient, "management", "permissions")) if err := checkForError(resp, err, errMessage); err != nil { return nil, err } return &result, nil } // UserAttributeContains checks if the given attribute value is set func UserAttributeContains(attributes map[string][]string, attribute, value string) bool { for _, item := range attributes[attribute] { if item == value { return true } } return false } // ----------- // Realm Roles // ----------- // CreateRealmRole creates a role in a realm func (g *GoCloak) CreateRealmRole(ctx context.Context, token string, realm string, role Role) (string, error) { const errMessage = "could not create realm role" resp, err := g.GetRequestWithBearerAuth(ctx, token). SetBody(role). Post(g.getAdminRealmURL(realm, "roles")) if err := checkForError(resp, err, errMessage); err != nil { return "", err } return getID(resp), nil } // GetRealmRole returns a role from a realm by role's name func (g *GoCloak) GetRealmRole(ctx context.Context, token, realm, roleName string) (*Role, error) { const errMessage = "could not get realm role" var result Role resp, err := g.GetRequestWithBearerAuth(ctx, token). SetResult(&result). Get(g.getAdminRealmURL(realm, "roles", roleName)) if err = checkForError(resp, err, errMessage); err != nil { return nil, err } return &result, nil } // GetRealmRoleByID returns a role from a realm by role's ID func (g *GoCloak) GetRealmRoleByID(ctx context.Context, token, realm, roleID string) (*Role, error) { const errMessage = "could not get realm role" var result Role resp, err := g.GetRequestWithBearerAuth(ctx, token). SetResult(&result). Get(g.getAdminRealmURL(realm, "roles-by-id", roleID)) if err := checkForError(resp, err, errMessage); err != nil { return nil, err } return &result, nil } // GetRealmRoles get all roles of the given realm. func (g *GoCloak) GetRealmRoles(ctx context.Context, token, realm string, params GetRoleParams) ([]*Role, error) { const errMessage = "could not get realm roles" var result []*Role queryParams, err := GetQueryParams(params) if err != nil { return nil, errors.Wrap(err, errMessage) } resp, err := g.GetRequestWithBearerAuth(ctx, token). SetResult(&result). SetQueryParams(queryParams). Get(g.getAdminRealmURL(realm, "roles")) if err := checkForError(resp, err, errMessage); err != nil { return nil, err } return result, nil } // GetRealmRolesByUserID returns all roles assigned to the given user func (g *GoCloak) GetRealmRolesByUserID(ctx context.Context, token, realm, userID string) ([]*Role, error) { const errMessage = "could not get realm roles by user id" var result []*Role resp, err := g.GetRequestWithBearerAuth(ctx, token). SetResult(&result). Get(g.getAdminRealmURL(realm, "users", userID, "role-mappings", "realm")) if err = checkForError(resp, err, errMessage); err != nil { return nil, err } return result, nil } // GetRealmRolesByGroupID returns all roles assigned to the given group func (g *GoCloak) GetRealmRolesByGroupID(ctx context.Context, token, realm, groupID string) ([]*Role, error) { const errMessage = "could not get realm roles by group id" var result []*Role resp, err := g.GetRequestWithBearerAuth(ctx, token). SetResult(&result). Get(g.getAdminRealmURL(realm, "groups", groupID, "role-mappings", "realm")) if err = checkForError(resp, err, errMessage); err != nil { return nil, err } return result, nil } // UpdateRealmRole updates a role in a realm func (g *GoCloak) UpdateRealmRole(ctx context.Context, token, realm, roleName string, role Role) error { const errMessage = "could not update realm role" resp, err := g.GetRequestWithBearerAuth(ctx, token). SetBody(role). Put(g.getAdminRealmURL(realm, "roles", roleName)) return checkForError(resp, err, errMessage) } // UpdateRealmRoleByID updates a role in a realm by role's ID func (g *GoCloak) UpdateRealmRoleByID(ctx context.Context, token, realm, roleID string, role Role) error { const errMessage = "could not update realm role" resp, err := g.GetRequestWithBearerAuth(ctx, token). SetBody(role). Put(g.getAdminRealmURL(realm, "roles-by-id", roleID)) return checkForError(resp, err, errMessage) } // DeleteRealmRole deletes a role in a realm by role's name func (g *GoCloak) DeleteRealmRole(ctx context.Context, token, realm, roleName string) error { const errMessage = "could not delete realm role" resp, err := g.GetRequestWithBearerAuth(ctx, token). Delete(g.getAdminRealmURL(realm, "roles", roleName)) return checkForError(resp, err, errMessage) } // AddRealmRoleToUser adds realm-level role mappings func (g *GoCloak) AddRealmRoleToUser(ctx context.Context, token, realm, userID string, roles []Role) error { const errMessage = "could not add realm role to user" resp, err := g.GetRequestWithBearerAuth(ctx, token). SetBody(roles). Post(g.getAdminRealmURL(realm, "users", userID, "role-mappings", "realm")) return checkForError(resp, err, errMessage) } // DeleteRealmRoleFromUser deletes realm-level role mappings func (g *GoCloak) DeleteRealmRoleFromUser(ctx context.Context, token, realm, userID string, roles []Role) error { const errMessage = "could not delete realm role from user" resp, err := g.GetRequestWithBearerAuth(ctx, token). SetBody(roles). Delete(g.getAdminRealmURL(realm, "users", userID, "role-mappings", "realm")) return checkForError(resp, err, errMessage) } // AddRealmRoleToGroup adds realm-level role mappings func (g *GoCloak) AddRealmRoleToGroup(ctx context.Context, token, realm, groupID string, roles []Role) error { const errMessage = "could not add realm role to group" resp, err := g.GetRequestWithBearerAuth(ctx, token). SetBody(roles). Post(g.getAdminRealmURL(realm, "groups", groupID, "role-mappings", "realm")) return checkForError(resp, err, errMessage) } // DeleteRealmRoleFromGroup deletes realm-level role mappings func (g *GoCloak) DeleteRealmRoleFromGroup(ctx context.Context, token, realm, groupID string, roles []Role) error { const errMessage = "could not delete realm role from group" resp, err := g.GetRequestWithBearerAuth(ctx, token). SetBody(roles). Delete(g.getAdminRealmURL(realm, "groups", groupID, "role-mappings", "realm")) return checkForError(resp, err, errMessage) } // AddRealmRoleComposite adds a role to the composite. func (g *GoCloak) AddRealmRoleComposite(ctx context.Context, token, realm, roleName string, roles []Role) error { const errMessage = "could not add realm role composite" resp, err := g.GetRequestWithBearerAuth(ctx, token). SetBody(roles). Post(g.getAdminRealmURL(realm, "roles", roleName, "composites")) return checkForError(resp, err, errMessage) } // DeleteRealmRoleComposite deletes a role from the composite. func (g *GoCloak) DeleteRealmRoleComposite(ctx context.Context, token, realm, roleName string, roles []Role) error { const errMessage = "could not delete realm role composite" resp, err := g.GetRequestWithBearerAuth(ctx, token). SetBody(roles). Delete(g.getAdminRealmURL(realm, "roles", roleName, "composites")) return checkForError(resp, err, errMessage) } // GetCompositeRealmRoles returns all realm composite roles associated with the given realm role func (g *GoCloak) GetCompositeRealmRoles(ctx context.Context, token, realm, roleName string) ([]*Role, error) { const errMessage = "could not get composite realm roles by role" var result []*Role resp, err := g.GetRequestWithBearerAuth(ctx, token). SetResult(&result). Get(g.getAdminRealmURL(realm, "roles", roleName, "composites")) if err = checkForError(resp, err, errMessage); err != nil { return nil, err } return result, nil } // GetCompositeRolesByRoleID returns all realm composite roles associated with the given client role func (g *GoCloak) GetCompositeRolesByRoleID(ctx context.Context, token, realm, roleID string) ([]*Role, error) { const errMessage = "could not get composite client roles by role id" var result []*Role resp, err := g.GetRequestWithBearerAuth(ctx, token). SetResult(&result). Get(g.getAdminRealmURL(realm, "roles-by-id", roleID, "composites")) if err = checkForError(resp, err, errMessage); err != nil { return nil, err } return result, nil } // GetCompositeRealmRolesByRoleID returns all realm composite roles associated with the given client role func (g *GoCloak) GetCompositeRealmRolesByRoleID(ctx context.Context, token, realm, roleID string) ([]*Role, error) { const errMessage = "could not get composite client roles by role id" var result []*Role resp, err := g.GetRequestWithBearerAuth(ctx, token). SetResult(&result). Get(g.getAdminRealmURL(realm, "roles-by-id", roleID, "composites", "realm")) if err = checkForError(resp, err, errMessage); err != nil { return nil, err } return result, nil } // GetCompositeRealmRolesByUserID returns all realm roles and composite roles assigned to the given user func (g *GoCloak) GetCompositeRealmRolesByUserID(ctx context.Context, token, realm, userID string) ([]*Role, error) { const errMessage = "could not get composite client roles by user id" var result []*Role resp, err := g.GetRequestWithBearerAuth(ctx, token). SetResult(&result). Get(g.getAdminRealmURL(realm, "users", userID, "role-mappings", "realm", "composite")) if err = checkForError(resp, err, errMessage); err != nil { return nil, err } return result, nil } // GetCompositeRealmRolesByGroupID returns all realm roles and composite roles assigned to the given group func (g *GoCloak) GetCompositeRealmRolesByGroupID(ctx context.Context, token, realm, groupID string) ([]*Role, error) { const errMessage = "could not get composite client roles by user id" var result []*Role resp, err := g.GetRequestWithBearerAuth(ctx, token). SetResult(&result). Get(g.getAdminRealmURL(realm, "groups", groupID, "role-mappings", "realm", "composite")) if err = checkForError(resp, err, errMessage); err != nil { return nil, err } return result, nil } // GetAvailableRealmRolesByUserID returns all available realm roles to the given user func (g *GoCloak) GetAvailableRealmRolesByUserID(ctx context.Context, token, realm, userID string) ([]*Role, error) { const errMessage = "could not get available client roles by user id" var result []*Role resp, err := g.GetRequestWithBearerAuth(ctx, token). SetResult(&result). Get(g.getAdminRealmURL(realm, "users", userID, "role-mappings", "realm", "available")) if err = checkForError(resp, err, errMessage); err != nil { return nil, err } return result, nil } // GetAvailableRealmRolesByGroupID returns all available realm roles to the given group func (g *GoCloak) GetAvailableRealmRolesByGroupID(ctx context.Context, token, realm, groupID string) ([]*Role, error) { const errMessage = "could not get available client roles by user id" var result []*Role resp, err := g.GetRequestWithBearerAuth(ctx, token). SetResult(&result). Get(g.getAdminRealmURL(realm, "groups", groupID, "role-mappings", "realm", "available")) if err = checkForError(resp, err, errMessage); err != nil { return nil, err } return result, nil } // ----- // Realm // ----- // GetRealm returns top-level representation of the realm func (g *GoCloak) GetRealm(ctx context.Context, token, realm string) (*RealmRepresentation, error) { const errMessage = "could not get realm" var result RealmRepresentation resp, err := g.GetRequestWithBearerAuth(ctx, token). SetResult(&result). Get(g.getAdminRealmURL(realm)) if err = checkForError(resp, err, errMessage); err != nil { return nil, err } return &result, nil } // GetRealms returns top-level representation of all realms func (g *GoCloak) GetRealms(ctx context.Context, token string) ([]*RealmRepresentation, error) { const errMessage = "could not get realms" var result []*RealmRepresentation resp, err := g.GetRequestWithBearerAuth(ctx, token). SetResult(&result). Get(g.getAdminRealmURL("")) if err = checkForError(resp, err, errMessage); err != nil { return nil, err } return result, nil } // CreateRealm creates a realm func (g *GoCloak) CreateRealm(ctx context.Context, token string, realm RealmRepresentation) (string, error) { const errMessage = "could not create realm" resp, err := g.GetRequestWithBearerAuth(ctx, token). SetBody(&realm). Post(g.getAdminRealmURL("")) if err := checkForError(resp, err, errMessage); err != nil { return "", err } return getID(resp), nil } // UpdateRealm updates a given realm func (g *GoCloak) UpdateRealm(ctx context.Context, token string, realm RealmRepresentation) error { const errMessage = "could not update realm" resp, err := g.GetRequestWithBearerAuth(ctx, token). SetBody(realm). Put(g.getAdminRealmURL(PString(realm.Realm))) return checkForError(resp, err, errMessage) } // DeleteRealm removes a realm func (g *GoCloak) DeleteRealm(ctx context.Context, token, realm string) error { const errMessage = "could not delete realm" resp, err := g.GetRequestWithBearerAuth(ctx, token). Delete(g.getAdminRealmURL(realm)) return checkForError(resp, err, errMessage) } // ClearRealmCache clears realm cache func (g *GoCloak) ClearRealmCache(ctx context.Context, token, realm string) error { const errMessage = "could not clear realm cache" resp, err := g.GetRequestWithBearerAuth(ctx, token). Post(g.getAdminRealmURL(realm, "clear-realm-cache")) return checkForError(resp, err, errMessage) } // ClearUserCache clears realm cache func (g *GoCloak) ClearUserCache(ctx context.Context, token, realm string) error { const errMessage = "could not clear user cache" resp, err := g.GetRequestWithBearerAuth(ctx, token). Post(g.getAdminRealmURL(realm, "clear-user-cache")) return checkForError(resp, err, errMessage) } // ClearKeysCache clears realm cache func (g *GoCloak) ClearKeysCache(ctx context.Context, token, realm string) error { const errMessage = "could not clear keys cache" resp, err := g.GetRequestWithBearerAuth(ctx, token). Post(g.getAdminRealmURL(realm, "clear-keys-cache")) return checkForError(resp, err, errMessage) } // GetAuthenticationFlows get all authentication flows from a realm func (g *GoCloak) GetAuthenticationFlows(ctx context.Context, token, realm string) ([]*AuthenticationFlowRepresentation, error) { const errMessage = "could not retrieve authentication flows" var result []*AuthenticationFlowRepresentation resp, err := g.GetRequestWithBearerAuth(ctx, token). SetResult(&result). Get(g.getAdminRealmURL(realm, "authentication", "flows")) if err := checkForError(resp, err, errMessage); err != nil { return nil, err } return result, nil } // GetAuthenticationFlow get an authentication flow with the given ID func (g *GoCloak) GetAuthenticationFlow(ctx context.Context, token, realm string, authenticationFlowID string) (*AuthenticationFlowRepresentation, error) { const errMessage = "could not retrieve authentication flows" var result *AuthenticationFlowRepresentation resp, err := g.GetRequestWithBearerAuth(ctx, token). SetResult(&result). Get(g.getAdminRealmURL(realm, "authentication", "flows", authenticationFlowID)) if err := checkForError(resp, err, errMessage); err != nil { return nil, err } return result, nil } // CreateAuthenticationFlow creates a new Authentication flow in a realm func (g *GoCloak) CreateAuthenticationFlow(ctx context.Context, token, realm string, flow AuthenticationFlowRepresentation) error { const errMessage = "could not create authentication flows" var result []*AuthenticationFlowRepresentation resp, err := g.GetRequestWithBearerAuth(ctx, token). SetResult(&result).SetBody(flow). Post(g.getAdminRealmURL(realm, "authentication", "flows")) return checkForError(resp, err, errMessage) } // UpdateAuthenticationFlow a given Authentication Flow func (g *GoCloak) UpdateAuthenticationFlow(ctx context.Context, token, realm string, flow AuthenticationFlowRepresentation, authenticationFlowID string) (*AuthenticationFlowRepresentation, error) { const errMessage = "could not create authentication flows" var result *AuthenticationFlowRepresentation resp, err := g.GetRequestWithBearerAuth(ctx, token). SetResult(&result).SetBody(flow). Put(g.getAdminRealmURL(realm, "authentication", "flows", authenticationFlowID)) if err = checkForError(resp, err, errMessage); err != nil { return nil, err } return result, nil } // DeleteAuthenticationFlow deletes a flow in a realm with the given ID func (g *GoCloak) DeleteAuthenticationFlow(ctx context.Context, token, realm, flowID string) error { const errMessage = "could not delete authentication flows" resp, err := g.GetRequestWithBearerAuth(ctx, token). Delete(g.getAdminRealmURL(realm, "authentication", "flows", flowID)) return checkForError(resp, err, errMessage) } // GetAuthenticationExecutions retrieves all executions of a given flow func (g *GoCloak) GetAuthenticationExecutions(ctx context.Context, token, realm, flow string) ([]*ModifyAuthenticationExecutionRepresentation, error) { const errMessage = "could not retrieve authentication flows" var result []*ModifyAuthenticationExecutionRepresentation resp, err := g.GetRequestWithBearerAuth(ctx, token). SetResult(&result). Get(g.getAdminRealmURL(realm, "authentication", "flows", flow, "executions")) if err := checkForError(resp, err, errMessage); err != nil { return nil, err } return result, nil } // CreateAuthenticationExecution creates a new execution for the given flow name in the given realm func (g *GoCloak) CreateAuthenticationExecution(ctx context.Context, token, realm, flow string, execution CreateAuthenticationExecutionRepresentation) error { const errMessage = "could not create authentication execution" resp, err := g.GetRequestWithBearerAuth(ctx, token).SetBody(execution). Post(g.getAdminRealmURL(realm, "authentication", "flows", flow, "executions", "execution")) return checkForError(resp, err, errMessage) } // UpdateAuthenticationExecution updates an authentication execution for the given flow in the given realm func (g *GoCloak) UpdateAuthenticationExecution(ctx context.Context, token, realm, flow string, execution ModifyAuthenticationExecutionRepresentation) error { const errMessage = "could not update authentication execution" resp, err := g.GetRequestWithBearerAuth(ctx, token).SetBody(execution). Put(g.getAdminRealmURL(realm, "authentication", "flows", flow, "executions")) return checkForError(resp, err, errMessage) } // DeleteAuthenticationExecution delete a single execution with the given ID func (g *GoCloak) DeleteAuthenticationExecution(ctx context.Context, token, realm, executionID string) error { const errMessage = "could not delete authentication execution" resp, err := g.GetRequestWithBearerAuth(ctx, token). Delete(g.getAdminRealmURL(realm, "authentication", "executions", executionID)) return checkForError(resp, err, errMessage) } // CreateAuthenticationExecutionFlow creates a new execution for the given flow name in the given realm func (g *GoCloak) CreateAuthenticationExecutionFlow(ctx context.Context, token, realm, flow string, executionFlow CreateAuthenticationExecutionFlowRepresentation) error { const errMessage = "could not create authentication execution flow" resp, err := g.GetRequestWithBearerAuth(ctx, token).SetBody(executionFlow). Post(g.getAdminRealmURL(realm, "authentication", "flows", flow, "executions", "flow")) return checkForError(resp, err, errMessage) } // ----- // Users // ----- // CreateUser creates the given user in the given realm and returns it's userID // Note: Keycloak has not documented what members of the User object are actually being accepted, when creating a user. // Things like RealmRoles must be attached using followup calls to the respective functions. func (g *GoCloak) CreateUser(ctx context.Context, token, realm string, user User) (string, error) { const errMessage = "could not create user" resp, err := g.GetRequestWithBearerAuth(ctx, token). SetBody(user). Post(g.getAdminRealmURL(realm, "users")) if err := checkForError(resp, err, errMessage); err != nil { return "", err } return getID(resp), nil } // DeleteUser delete a given user func (g *GoCloak) DeleteUser(ctx context.Context, token, realm, userID string) error { const errMessage = "could not delete user" resp, err := g.GetRequestWithBearerAuth(ctx, token). Delete(g.getAdminRealmURL(realm, "users", userID)) return checkForError(resp, err, errMessage) } // GetUserByID fetches a user from the given realm with the given userID func (g *GoCloak) GetUserByID(ctx context.Context, accessToken, realm, userID string) (*User, error) { const errMessage = "could not get user by id" if userID == "" { return nil, errors.Wrap(errors.New("userID shall not be empty"), errMessage) } var result User resp, err := g.GetRequestWithBearerAuth(ctx, accessToken). SetResult(&result). Get(g.getAdminRealmURL(realm, "users", userID)) if err := checkForError(resp, err, errMessage); err != nil { return nil, err } return &result, nil } // GetUserCount gets the user count in the realm func (g *GoCloak) GetUserCount(ctx context.Context, token string, realm string, params GetUsersParams) (int, error) { const errMessage = "could not get user count" var result int queryParams, err := GetQueryParams(params) if err != nil { return 0, errors.Wrap(err, errMessage) } resp, err := g.GetRequestWithBearerAuth(ctx, token). SetResult(&result). SetQueryParams(queryParams). Get(g.getAdminRealmURL(realm, "users", "count")) if err := checkForError(resp, err, errMessage); err != nil { return -1, errors.Wrap(err, errMessage) } return result, nil } // GetUserGroups get all groups for user func (g *GoCloak) GetUserGroups(ctx context.Context, token, realm, userID string, params GetGroupsParams) ([]*Group, error) { const errMessage = "could not get user groups" var result []*Group queryParams, err := GetQueryParams(params) if err != nil { return nil, errors.Wrap(err, errMessage) } resp, err := g.GetRequestWithBearerAuth(ctx, token). SetResult(&result). SetQueryParams(queryParams). Get(g.getAdminRealmURL(realm, "users", userID, "groups")) if err := checkForError(resp, err, errMessage); err != nil { return nil, err } return result, nil } // GetUsers get all users in realm func (g *GoCloak) GetUsers(ctx context.Context, token, realm string, params GetUsersParams) ([]*User, error) { const errMessage = "could not get users" var result []*User queryParams, err := GetQueryParams(params) if err != nil { return nil, errors.Wrap(err, errMessage) } resp, err := g.GetRequestWithBearerAuth(ctx, token). SetResult(&result). SetQueryParams(queryParams). Get(g.getAdminRealmURL(realm, "users")) if err := checkForError(resp, err, errMessage); err != nil { return nil, err } return result, nil } // GetUsersByRoleName returns all users have a given role func (g *GoCloak) GetUsersByRoleName(ctx context.Context, token, realm, roleName string, params GetUsersByRoleParams) ([]*User, error) { const errMessage = "could not get users by role name" var result []*User queryParams, err := GetQueryParams(params) if err != nil { return nil, errors.Wrap(err, errMessage) } resp, err := g.GetRequestWithBearerAuth(ctx, token). SetResult(&result). SetQueryParams(queryParams). Get(g.getAdminRealmURL(realm, "roles", roleName, "users")) if err := checkForError(resp, err, errMessage); err != nil { return nil, err } return result, nil } // GetUsersByClientRoleName returns all users have a given client role func (g *GoCloak) GetUsersByClientRoleName(ctx context.Context, token, realm, idOfClient, roleName string, params GetUsersByRoleParams) ([]*User, error) { const errMessage = "could not get users by client role name" var result []*User queryParams, err := GetQueryParams(params) if err != nil { return nil, err } resp, err := g.GetRequestWithBearerAuth(ctx, token). SetResult(&result). SetQueryParams(queryParams). Get(g.getAdminRealmURL(realm, "clients", idOfClient, "roles", roleName, "users")) if err := checkForError(resp, err, errMessage); err != nil { return nil, err } return result, nil } // SetPassword sets a new password for the user with the given id. Needs elevated privileges func (g *GoCloak) SetPassword(ctx context.Context, token, userID, realm, password string, temporary bool) error { const errMessage = "could not set password" requestBody := SetPasswordRequest{Password: &password, Temporary: &temporary, Type: StringP("password")} resp, err := g.GetRequestWithBearerAuth(ctx, token). SetBody(requestBody). Put(g.getAdminRealmURL(realm, "users", userID, "reset-password")) return checkForError(resp, err, errMessage) } // UpdateUser updates a given user func (g *GoCloak) UpdateUser(ctx context.Context, token, realm string, user User) error { const errMessage = "could not update user" resp, err := g.GetRequestWithBearerAuth(ctx, token). SetBody(user). Put(g.getAdminRealmURL(realm, "users", PString(user.ID))) return checkForError(resp, err, errMessage) } // AddUserToGroup puts given user to given group func (g *GoCloak) AddUserToGroup(ctx context.Context, token, realm, userID, groupID string) error { const errMessage = "could not add user to group" resp, err := g.GetRequestWithBearerAuth(ctx, token). Put(g.getAdminRealmURL(realm, "users", userID, "groups", groupID)) return checkForError(resp, err, errMessage) } // DeleteUserFromGroup deletes given user from given group func (g *GoCloak) DeleteUserFromGroup(ctx context.Context, token, realm, userID, groupID string) error { const errMessage = "could not delete user from group" resp, err := g.GetRequestWithBearerAuth(ctx, token). Delete(g.getAdminRealmURL(realm, "users", userID, "groups", groupID)) return checkForError(resp, err, errMessage) } // GetUserSessions returns user sessions associated with the user func (g *GoCloak) GetUserSessions(ctx context.Context, token, realm, userID string) ([]*UserSessionRepresentation, error) { const errMessage = "could not get user sessions" var res []*UserSessionRepresentation resp, err := g.GetRequestWithBearerAuth(ctx, token). SetResult(&res). Get(g.getAdminRealmURL(realm, "users", userID, "sessions")) if err := checkForError(resp, err, errMessage); err != nil { return nil, err } return res, nil } // GetUserOfflineSessionsForClient returns offline sessions associated with the user and client func (g *GoCloak) GetUserOfflineSessionsForClient(ctx context.Context, token, realm, userID, idOfClient string) ([]*UserSessionRepresentation, error) { const errMessage = "could not get user offline sessions for client" var res []*UserSessionRepresentation resp, err := g.GetRequestWithBearerAuth(ctx, token). SetResult(&res). Get(g.getAdminRealmURL(realm, "users", userID, "offline-sessions", idOfClient)) if err := checkForError(resp, err, errMessage); err != nil { return nil, err } return res, nil } // AddClientRolesToUser adds client-level role mappings func (g *GoCloak) AddClientRolesToUser(ctx context.Context, token, realm, idOfClient, userID string, roles []Role) error { const errMessage = "could not add client role to user" resp, err := g.GetRequestWithBearerAuth(ctx, token). SetBody(roles). Post(g.getAdminRealmURL(realm, "users", userID, "role-mappings", "clients", idOfClient)) return checkForError(resp, err, errMessage) } // AddClientRoleToUser adds client-level role mappings // // Deprecated: replaced by AddClientRolesToUser func (g *GoCloak) AddClientRoleToUser(ctx context.Context, token, realm, idOfClient, userID string, roles []Role) error { return g.AddClientRolesToUser(ctx, token, realm, idOfClient, userID, roles) } // AddClientRolesToGroup adds a client role to the group func (g *GoCloak) AddClientRolesToGroup(ctx context.Context, token, realm, idOfClient, groupID string, roles []Role) error { const errMessage = "could not add client role to group" resp, err := g.GetRequestWithBearerAuth(ctx, token). SetBody(roles). Post(g.getAdminRealmURL(realm, "groups", groupID, "role-mappings", "clients", idOfClient)) return checkForError(resp, err, errMessage) } // AddClientRoleToGroup adds a client role to the group // // Deprecated: replaced by AddClientRolesToGroup func (g *GoCloak) AddClientRoleToGroup(ctx context.Context, token, realm, idOfClient, groupID string, roles []Role) error { return g.AddClientRolesToGroup(ctx, token, realm, idOfClient, groupID, roles) } // DeleteClientRolesFromUser adds client-level role mappings func (g *GoCloak) DeleteClientRolesFromUser(ctx context.Context, token, realm, idOfClient, userID string, roles []Role) error { const errMessage = "could not delete client role from user" resp, err := g.GetRequestWithBearerAuth(ctx, token). SetBody(roles). Delete(g.getAdminRealmURL(realm, "users", userID, "role-mappings", "clients", idOfClient)) return checkForError(resp, err, errMessage) } // DeleteClientRoleFromUser adds client-level role mappings // // Deprecated: replaced by DeleteClientRolesFrom func (g *GoCloak) DeleteClientRoleFromUser(ctx context.Context, token, realm, idOfClient, userID string, roles []Role) error { return g.DeleteClientRolesFromUser(ctx, token, realm, idOfClient, userID, roles) } // DeleteClientRoleFromGroup removes a client role from from the group func (g *GoCloak) DeleteClientRoleFromGroup(ctx context.Context, token, realm, idOfClient, groupID string, roles []Role) error { const errMessage = "could not client role from group" resp, err := g.GetRequestWithBearerAuth(ctx, token). SetBody(roles). Delete(g.getAdminRealmURL(realm, "groups", groupID, "role-mappings", "clients", idOfClient)) return checkForError(resp, err, errMessage) } // AddClientRoleComposite adds roles as composite func (g *GoCloak) AddClientRoleComposite(ctx context.Context, token, realm, roleID string, roles []Role) error { const errMessage = "could not add client role composite" resp, err := g.GetRequestWithBearerAuth(ctx, token). SetBody(roles). Post(g.getAdminRealmURL(realm, "roles-by-id", roleID, "composites")) return checkForError(resp, err, errMessage) } // DeleteClientRoleComposite deletes composites from a role func (g *GoCloak) DeleteClientRoleComposite(ctx context.Context, token, realm, roleID string, roles []Role) error { const errMessage = "could not delete client role composite" resp, err := g.GetRequestWithBearerAuth(ctx, token). SetBody(roles). Delete(g.getAdminRealmURL(realm, "roles-by-id", roleID, "composites")) return checkForError(resp, err, errMessage) } // GetUserFederatedIdentities gets all user federated identities func (g *GoCloak) GetUserFederatedIdentities(ctx context.Context, token, realm, userID string) ([]*FederatedIdentityRepresentation, error) { const errMessage = "could not get user federated identities" var res []*FederatedIdentityRepresentation resp, err := g.GetRequestWithBearerAuth(ctx, token). SetResult(&res). Get(g.getAdminRealmURL(realm, "users", userID, "federated-identity")) if err := checkForError(resp, err, errMessage); err != nil { return nil, err } return res, err } // CreateUserFederatedIdentity creates an user federated identity func (g *GoCloak) CreateUserFederatedIdentity(ctx context.Context, token, realm, userID, providerID string, federatedIdentityRep FederatedIdentityRepresentation) error { const errMessage = "could not create user federeated identity" resp, err := g.GetRequestWithBearerAuth(ctx, token). SetBody(federatedIdentityRep). Post(g.getAdminRealmURL(realm, "users", userID, "federated-identity", providerID)) return checkForError(resp, err, errMessage) } // DeleteUserFederatedIdentity deletes an user federated identity func (g *GoCloak) DeleteUserFederatedIdentity(ctx context.Context, token, realm, userID, providerID string) error { const errMessage = "could not delete user federeated identity" resp, err := g.GetRequestWithBearerAuth(ctx, token). Delete(g.getAdminRealmURL(realm, "users", userID, "federated-identity", providerID)) return checkForError(resp, err, errMessage) } // GetUserBruteForceDetectionStatus fetches a user status regarding brute force protection func (g *GoCloak) GetUserBruteForceDetectionStatus(ctx context.Context, accessToken, realm, userID string) (*BruteForceStatus, error) { const errMessage = "could not brute force detection Status" var result BruteForceStatus resp, err := g.GetRequestWithBearerAuth(ctx, accessToken). SetResult(&result). Get(g.getAttackDetectionURL(realm, "users", userID)) if err := checkForError(resp, err, errMessage); err != nil { return nil, err } return &result, nil } // ------------------ // Identity Providers // ------------------ // CreateIdentityProvider creates an identity provider in a realm func (g *GoCloak) CreateIdentityProvider(ctx context.Context, token string, realm string, providerRep IdentityProviderRepresentation) (string, error) { const errMessage = "could not create identity provider" resp, err := g.GetRequestWithBearerAuth(ctx, token). SetBody(providerRep). Post(g.getAdminRealmURL(realm, "identity-provider", "instances")) if err := checkForError(resp, err, errMessage); err != nil { return "", err } return getID(resp), nil } // GetIdentityProviders returns list of identity providers in a realm func (g *GoCloak) GetIdentityProviders(ctx context.Context, token, realm string) ([]*IdentityProviderRepresentation, error) { const errMessage = "could not get identity providers" var result []*IdentityProviderRepresentation resp, err := g.GetRequestWithBearerAuth(ctx, token). SetResult(&result). Get(g.getAdminRealmURL(realm, "identity-provider", "instances")) if err := checkForError(resp, err, errMessage); err != nil { return nil, err } return result, nil } // GetIdentityProvider gets the identity provider in a realm func (g *GoCloak) GetIdentityProvider(ctx context.Context, token, realm, alias string) (*IdentityProviderRepresentation, error) { const errMessage = "could not get identity provider" var result IdentityProviderRepresentation resp, err := g.GetRequestWithBearerAuth(ctx, token). SetResult(&result). Get(g.getAdminRealmURL(realm, "identity-provider", "instances", alias)) if err := checkForError(resp, err, errMessage); err != nil { return nil, err } return &result, nil } // UpdateIdentityProvider updates the identity provider in a realm func (g *GoCloak) UpdateIdentityProvider(ctx context.Context, token, realm, alias string, providerRep IdentityProviderRepresentation) error { const errMessage = "could not update identity provider" resp, err := g.GetRequestWithBearerAuth(ctx, token). SetBody(providerRep). Put(g.getAdminRealmURL(realm, "identity-provider", "instances", alias)) return checkForError(resp, err, errMessage) } // DeleteIdentityProvider deletes the identity provider in a realm func (g *GoCloak) DeleteIdentityProvider(ctx context.Context, token, realm, alias string) error { const errMessage = "could not delete identity provider" resp, err := g.GetRequestWithBearerAuth(ctx, token). Delete(g.getAdminRealmURL(realm, "identity-provider", "instances", alias)) return checkForError(resp, err, errMessage) } // ExportIDPPublicBrokerConfig exports the broker config for a given alias func (g *GoCloak) ExportIDPPublicBrokerConfig(ctx context.Context, token, realm, alias string) (*string, error) { const errMessage = "could not get public identity provider configuration" resp, err := g.GetRequestWithBearerAuthXMLHeader(ctx, token). Get(g.getAdminRealmURL(realm, "identity-provider", "instances", alias, "export")) if err := checkForError(resp, err, errMessage); err != nil { return nil, err } result := resp.String() return &result, nil } // ImportIdentityProviderConfig parses and returns the identity provider config at a given URL func (g *GoCloak) ImportIdentityProviderConfig(ctx context.Context, token, realm, fromURL, providerID string) (map[string]string, error) { const errMessage = "could not import config" result := make(map[string]string) resp, err := g.GetRequestWithBearerAuth(ctx, token). SetResult(&result). SetBody(map[string]string{ "fromUrl": fromURL, "providerId": providerID, }). Post(g.getAdminRealmURL(realm, "identity-provider", "import-config")) if err := checkForError(resp, err, errMessage); err != nil { return nil, err } return result, nil } // ImportIdentityProviderConfigFromFile parses and returns the identity provider config from a given file func (g *GoCloak) ImportIdentityProviderConfigFromFile(ctx context.Context, token, realm, providerID, fileName string, fileBody io.Reader) (map[string]string, error) { const errMessage = "could not import config" result := make(map[string]string) resp, err := g.GetRequestWithBearerAuth(ctx, token). SetResult(&result). SetFileReader("file", fileName, fileBody). SetFormData(map[string]string{ "providerId": providerID, }). Post(g.getAdminRealmURL(realm, "identity-provider", "import-config")) if err := checkForError(resp, err, errMessage); err != nil { return nil, err } return result, nil } // CreateIdentityProviderMapper creates an instance of an identity provider mapper associated with the given alias func (g *GoCloak) CreateIdentityProviderMapper(ctx context.Context, token, realm, alias string, mapper IdentityProviderMapper) (string, error) { const errMessage = "could not create mapper for identity provider" resp, err := g.GetRequestWithBearerAuth(ctx, token). SetBody(mapper). Post(g.getAdminRealmURL(realm, "identity-provider", "instances", alias, "mappers")) if err := checkForError(resp, err, errMessage); err != nil { return "", err } return getID(resp), nil } // GetIdentityProviderMapper gets the mapper by id for the given identity provider alias in a realm func (g *GoCloak) GetIdentityProviderMapper(ctx context.Context, token string, realm string, alias string, mapperID string) (*IdentityProviderMapper, error) { const errMessage = "could not get identity provider mapper" result := IdentityProviderMapper{} resp, err := g.GetRequestWithBearerAuth(ctx, token). SetResult(&result). Get(g.getAdminRealmURL(realm, "identity-provider", "instances", alias, "mappers", mapperID)) if err := checkForError(resp, err, errMessage); err != nil { return nil, err } return &result, nil } // DeleteIdentityProviderMapper deletes an instance of an identity provider mapper associated with the given alias and mapper ID func (g *GoCloak) DeleteIdentityProviderMapper(ctx context.Context, token, realm, alias, mapperID string) error { const errMessage = "could not delete mapper for identity provider" resp, err := g.GetRequestWithBearerAuth(ctx, token). Delete(g.getAdminRealmURL(realm, "identity-provider", "instances", alias, "mappers", mapperID)) return checkForError(resp, err, errMessage) } // GetIdentityProviderMappers returns list of mappers associated with an identity provider func (g *GoCloak) GetIdentityProviderMappers(ctx context.Context, token, realm, alias string) ([]*IdentityProviderMapper, error) { const errMessage = "could not get identity provider mappers" var result []*IdentityProviderMapper resp, err := g.GetRequestWithBearerAuth(ctx, token). SetResult(&result). Get(g.getAdminRealmURL(realm, "identity-provider", "instances", alias, "mappers")) if err := checkForError(resp, err, errMessage); err != nil { return nil, err } return result, nil } // GetIdentityProviderMapperByID gets the mapper of an identity provider func (g *GoCloak) GetIdentityProviderMapperByID(ctx context.Context, token, realm, alias, mapperID string) (*IdentityProviderMapper, error) { const errMessage = "could not get identity provider mappers" var result IdentityProviderMapper resp, err := g.GetRequestWithBearerAuth(ctx, token). SetResult(&result). Get(g.getAdminRealmURL(realm, "identity-provider", "instances", alias, "mappers", mapperID)) if err := checkForError(resp, err, errMessage); err != nil { return nil, err } return &result, nil } // UpdateIdentityProviderMapper updates mapper of an identity provider func (g *GoCloak) UpdateIdentityProviderMapper(ctx context.Context, token, realm, alias string, mapper IdentityProviderMapper) error { const errMessage = "could not update identity provider mapper" resp, err := g.GetRequestWithBearerAuth(ctx, token). SetBody(mapper). Put(g.getAdminRealmURL(realm, "identity-provider", "instances", alias, "mappers", PString(mapper.ID))) return checkForError(resp, err, errMessage) } // ------------------ // Protection API // ------------------ // GetResource returns a client's resource with the given id, using access token from admin func (g *GoCloak) GetResource(ctx context.Context, token, realm, idOfClient, resourceID string) (*ResourceRepresentation, error) { const errMessage = "could not get resource" var result ResourceRepresentation resp, err := g.GetRequestWithBearerAuth(ctx, token). SetResult(&result). Get(g.getAdminRealmURL(realm, "clients", idOfClient, "authz", "resource-server", "resource", resourceID)) if err := checkForError(resp, err, errMessage); err != nil { return nil, err } return &result, nil } // GetResourceClient returns a client's resource with the given id, using access token from client func (g *GoCloak) GetResourceClient(ctx context.Context, token, realm, resourceID string) (*ResourceRepresentation, error) { const errMessage = "could not get resource" var result ResourceRepresentation resp, err := g.GetRequestWithBearerAuth(ctx, token). SetResult(&result). Get(g.getRealmURL(realm, "authz", "protection", "resource_set", resourceID)) // http://${host}:${port}/auth/realms/${realm_name}/authz/protection/resource_set/{resource_id} if err := checkForError(resp, err, errMessage); err != nil { return nil, err } return &result, nil } // GetResources returns resources associated with the client, using access token from admin func (g *GoCloak) GetResources(ctx context.Context, token, realm, idOfClient string, params GetResourceParams) ([]*ResourceRepresentation, error) { const errMessage = "could not get resources" queryParams, err := GetQueryParams(params) if err != nil { return nil, err } var result []*ResourceRepresentation resp, err := g.GetRequestWithBearerAuth(ctx, token). SetResult(&result). SetQueryParams(queryParams). Get(g.getAdminRealmURL(realm, "clients", idOfClient, "authz", "resource-server", "resource")) if err := checkForError(resp, err, errMessage); err != nil { return nil, err } return result, nil } // GetResourcesClient returns resources associated with the client, using access token from client func (g *GoCloak) GetResourcesClient(ctx context.Context, token, realm string, params GetResourceParams) ([]*ResourceRepresentation, error) { const errMessage = "could not get resources" queryParams, err := GetQueryParams(params) if err != nil { return nil, err } var result []*ResourceRepresentation var resourceIDs []string resp, err := g.GetRequestWithBearerAuth(ctx, token). SetResult(&resourceIDs). SetQueryParams(queryParams). Get(g.getRealmURL(realm, "authz", "protection", "resource_set")) if err := checkForError(resp, err, errMessage); err != nil { return nil, err } for _, resourceID := range resourceIDs { resource, err := g.GetResourceClient(ctx, token, realm, resourceID) if err == nil { result = append(result, resource) } } return result, nil } // GetResourceServer returns resource server settings. // The access token must have the realm view_clients role on its service // account to be allowed to call this endpoint. func (g *GoCloak) GetResourceServer(ctx context.Context, token, realm, idOfClient string) (*ResourceServerRepresentation, error) { const errMessage = "could not get resource server settings" var result *ResourceServerRepresentation resp, err := g.GetRequestWithBearerAuth(ctx, token). SetResult(&result). Get(g.getAdminRealmURL(realm, "clients", idOfClient, "authz", "resource-server", "settings")) if err := checkForError(resp, err, errMessage); err != nil { return nil, err } return result, nil } // UpdateResource updates a resource associated with the client, using access token from admin func (g *GoCloak) UpdateResource(ctx context.Context, token, realm, idOfClient string, resource ResourceRepresentation) error { const errMessage = "could not update resource" if NilOrEmpty(resource.ID) { return errors.New("ID of a resource required") } resp, err := g.GetRequestWithBearerAuth(ctx, token). SetBody(resource). Put(g.getAdminRealmURL(realm, "clients", idOfClient, "authz", "resource-server", "resource", *(resource.ID))) return checkForError(resp, err, errMessage) } // UpdateResourceClient updates a resource associated with the client, using access token from client func (g *GoCloak) UpdateResourceClient(ctx context.Context, token, realm string, resource ResourceRepresentation) error { const errMessage = "could not update resource" if NilOrEmpty(resource.ID) { return errors.New("ID of a resource required") } resp, err := g.GetRequestWithBearerAuth(ctx, token). SetBody(resource). Put(g.getRealmURL(realm, "authz", "protection", "resource_set", *(resource.ID))) return checkForError(resp, err, errMessage) } // CreateResource creates a resource associated with the client, using access token from admin func (g *GoCloak) CreateResource(ctx context.Context, token, realm string, idOfClient string, resource ResourceRepresentation) (*ResourceRepresentation, error) { const errMessage = "could not create resource" var result ResourceRepresentation resp, err := g.GetRequestWithBearerAuth(ctx, token). SetResult(&result). SetBody(resource). Post(g.getAdminRealmURL(realm, "clients", idOfClient, "authz", "resource-server", "resource")) if err := checkForError(resp, err, errMessage); err != nil { return nil, err } return &result, nil } // CreateResourceClient creates a resource associated with the client, using access token from client func (g *GoCloak) CreateResourceClient(ctx context.Context, token, realm string, resource ResourceRepresentation) (*ResourceRepresentation, error) { const errMessage = "could not create resource" var result ResourceRepresentation resp, err := g.GetRequestWithBearerAuth(ctx, token). SetResult(&result). SetBody(resource). Post(g.getRealmURL(realm, "authz", "protection", "resource_set")) if err := checkForError(resp, err, errMessage); err != nil { return nil, err } return &result, nil } // DeleteResource deletes a resource associated with the client (using an admin token) func (g *GoCloak) DeleteResource(ctx context.Context, token, realm, idOfClient, resourceID string) error { const errMessage = "could not delete resource" resp, err := g.GetRequestWithBearerAuth(ctx, token). Delete(g.getAdminRealmURL(realm, "clients", idOfClient, "authz", "resource-server", "resource", resourceID)) return checkForError(resp, err, errMessage) } // DeleteResourceClient deletes a resource associated with the client (using a client token) func (g *GoCloak) DeleteResourceClient(ctx context.Context, token, realm, resourceID string) error { const errMessage = "could not delete resource" resp, err := g.GetRequestWithBearerAuth(ctx, token). Delete(g.getRealmURL(realm, "authz", "protection", "resource_set", resourceID)) return checkForError(resp, err, errMessage) } // GetScope returns a client's scope with the given id func (g *GoCloak) GetScope(ctx context.Context, token, realm, idOfClient, scopeID string) (*ScopeRepresentation, error) { const errMessage = "could not get scope" var result ScopeRepresentation resp, err := g.GetRequestWithBearerAuth(ctx, token). SetResult(&result). Get(g.getAdminRealmURL(realm, "clients", idOfClient, "authz", "resource-server", "scope", scopeID)) if err := checkForError(resp, err, errMessage); err != nil { return nil, err } return &result, nil } // GetScopes returns scopes associated with the client func (g *GoCloak) GetScopes(ctx context.Context, token, realm, idOfClient string, params GetScopeParams) ([]*ScopeRepresentation, error) { const errMessage = "could not get scopes" queryParams, err := GetQueryParams(params) if err != nil { return nil, err } var result []*ScopeRepresentation resp, err := g.GetRequestWithBearerAuth(ctx, token). SetResult(&result). SetQueryParams(queryParams). Get(g.getAdminRealmURL(realm, "clients", idOfClient, "authz", "resource-server", "scope")) if err := checkForError(resp, err, errMessage); err != nil { return nil, err } return result, nil } // CreateScope creates a scope associated with the client func (g *GoCloak) CreateScope(ctx context.Context, token, realm, idOfClient string, scope ScopeRepresentation) (*ScopeRepresentation, error) { const errMessage = "could not create scope" var result ScopeRepresentation resp, err := g.GetRequestWithBearerAuth(ctx, token). SetResult(&result). SetBody(scope). Post(g.getAdminRealmURL(realm, "clients", idOfClient, "authz", "resource-server", "scope")) if err := checkForError(resp, err, errMessage); err != nil { return nil, err } return &result, nil } // GetPermissionScope gets the permission scope associated with the client func (g *GoCloak) GetPermissionScope(ctx context.Context, token, realm, idOfClient string, idOfScope string) (*PolicyRepresentation, error) { const errMessage = "could not get permission scope" var result PolicyRepresentation resp, err := g.GetRequestWithBearerAuth(ctx, token). SetResult(&result). SetBody(result). Get(g.getAdminRealmURL(realm, "clients", idOfClient, "authz", "resource-server", "permission", "scope", idOfScope)) if err := checkForError(resp, err, errMessage); err != nil { return nil, err } return &result, nil } // UpdatePermissionScope updates a permission scope associated with the client func (g *GoCloak) UpdatePermissionScope(ctx context.Context, token, realm, idOfClient string, idOfScope string, policy PolicyRepresentation) error { const errMessage = "could not create permission scope" resp, err := g.GetRequestWithBearerAuth(ctx, token). SetBody(policy). Put(g.getAdminRealmURL(realm, "clients", idOfClient, "authz", "resource-server", "permission", "scope", idOfScope)) return checkForError(resp, err, errMessage) } // UpdateScope updates a scope associated with the client func (g *GoCloak) UpdateScope(ctx context.Context, token, realm, idOfClient string, scope ScopeRepresentation) error { const errMessage = "could not update scope" if NilOrEmpty(scope.ID) { return errors.New("ID of a scope required") } resp, err := g.GetRequestWithBearerAuth(ctx, token). SetBody(scope). Put(g.getAdminRealmURL(realm, "clients", idOfClient, "authz", "resource-server", "scope", *(scope.ID))) return checkForError(resp, err, errMessage) } // DeleteScope deletes a scope associated with the client func (g *GoCloak) DeleteScope(ctx context.Context, token, realm, idOfClient, scopeID string) error { const errMessage = "could not delete scope" resp, err := g.GetRequestWithBearerAuth(ctx, token). Delete(g.getAdminRealmURL(realm, "clients", idOfClient, "authz", "resource-server", "scope", scopeID)) return checkForError(resp, err, errMessage) } // GetPolicy returns a client's policy with the given id func (g *GoCloak) GetPolicy(ctx context.Context, token, realm, idOfClient, policyID string) (*PolicyRepresentation, error) { const errMessage = "could not get policy" var result PolicyRepresentation resp, err := g.GetRequestWithBearerAuth(ctx, token). SetResult(&result). Get(g.getAdminRealmURL(realm, "clients", idOfClient, "authz", "resource-server", "policy", policyID)) if err := checkForError(resp, err, errMessage); err != nil { return nil, err } return &result, nil } // GetPolicies returns policies associated with the client func (g *GoCloak) GetPolicies(ctx context.Context, token, realm, idOfClient string, params GetPolicyParams) ([]*PolicyRepresentation, error) { const errMessage = "could not get policies" queryParams, err := GetQueryParams(params) if err != nil { return nil, errors.Wrap(err, errMessage) } path := []string{"clients", idOfClient, "authz", "resource-server", "policy"} if !NilOrEmpty(params.Type) { path = append(path, *params.Type) } var result []*PolicyRepresentation resp, err := g.GetRequestWithBearerAuth(ctx, token). SetResult(&result). SetQueryParams(queryParams). Get(g.getAdminRealmURL(realm, path...)) if err := checkForError(resp, err, errMessage); err != nil { return nil, err } return result, nil } // CreatePolicy creates a policy associated with the client func (g *GoCloak) CreatePolicy(ctx context.Context, token, realm, idOfClient string, policy PolicyRepresentation) (*PolicyRepresentation, error) { const errMessage = "could not create policy" if NilOrEmpty(policy.Type) { return nil, errors.New("type of a policy required") } var result PolicyRepresentation resp, err := g.GetRequestWithBearerAuth(ctx, token). SetResult(&result). SetBody(policy). Post(g.getAdminRealmURL(realm, "clients", idOfClient, "authz", "resource-server", "policy", *(policy.Type))) if err := checkForError(resp, err, errMessage); err != nil { return nil, err } return &result, nil } // UpdatePolicy updates a policy associated with the client func (g *GoCloak) UpdatePolicy(ctx context.Context, token, realm, idOfClient string, policy PolicyRepresentation) error { const errMessage = "could not update policy" if NilOrEmpty(policy.ID) { return errors.New("ID of a policy required") } resp, err := g.GetRequestWithBearerAuth(ctx, token). SetBody(policy). Put(g.getAdminRealmURL(realm, "clients", idOfClient, "authz", "resource-server", "policy", *(policy.Type), *(policy.ID))) return checkForError(resp, err, errMessage) } // DeletePolicy deletes a policy associated with the client func (g *GoCloak) DeletePolicy(ctx context.Context, token, realm, idOfClient, policyID string) error { const errMessage = "could not delete policy" resp, err := g.GetRequestWithBearerAuth(ctx, token). Delete(g.getAdminRealmURL(realm, "clients", idOfClient, "authz", "resource-server", "policy", policyID)) return checkForError(resp, err, errMessage) } // GetAuthorizationPolicyAssociatedPolicies returns a client's associated policies of specific policy with the given policy id, using access token from admin func (g *GoCloak) GetAuthorizationPolicyAssociatedPolicies(ctx context.Context, token, realm, idOfClient, policyID string) ([]*PolicyRepresentation, error) { const errMessage = "could not get policy associated policies" var result []*PolicyRepresentation resp, err := g.GetRequestWithBearerAuth(ctx, token). SetResult(&result). Get(g.getAdminRealmURL(realm, "clients", idOfClient, "authz", "resource-server", "policy", policyID, "associatedPolicies")) if err := checkForError(resp, err, errMessage); err != nil { return nil, err } return result, nil } // GetAuthorizationPolicyResources returns a client's resources of specific policy with the given policy id, using access token from admin func (g *GoCloak) GetAuthorizationPolicyResources(ctx context.Context, token, realm, idOfClient, policyID string) ([]*PolicyResourceRepresentation, error) { const errMessage = "could not get policy resources" var result []*PolicyResourceRepresentation resp, err := g.GetRequestWithBearerAuth(ctx, token). SetResult(&result). Get(g.getAdminRealmURL(realm, "clients", idOfClient, "authz", "resource-server", "policy", policyID, "resources")) if err := checkForError(resp, err, errMessage); err != nil { return nil, err } return result, nil } // GetAuthorizationPolicyScopes returns a client's scopes of specific policy with the given policy id, using access token from admin func (g *GoCloak) GetAuthorizationPolicyScopes(ctx context.Context, token, realm, idOfClient, policyID string) ([]*PolicyScopeRepresentation, error) { const errMessage = "could not get policy scopes" var result []*PolicyScopeRepresentation resp, err := g.GetRequestWithBearerAuth(ctx, token). SetResult(&result). Get(g.getAdminRealmURL(realm, "clients", idOfClient, "authz", "resource-server", "policy", policyID, "scopes")) if err := checkForError(resp, err, errMessage); err != nil { return nil, err } return result, nil } // GetResourcePolicy updates a permission for a specific resource, using token obtained by Resource Owner Password Credentials Grant or Token exchange func (g *GoCloak) GetResourcePolicy(ctx context.Context, token, realm, permissionID string) (*ResourcePolicyRepresentation, error) { const errMessage = "could not get resource policy" var result ResourcePolicyRepresentation resp, err := g.GetRequestWithBearerAuthNoCache(ctx, token). SetResult(&result). Get(g.getRealmURL(realm, "authz", "protection", "uma-policy", permissionID)) if err := checkForError(resp, err, errMessage); err != nil { return nil, err } return &result, nil } // GetResourcePolicies returns resources associated with the client, using token obtained by Resource Owner Password Credentials Grant or Token exchange func (g *GoCloak) GetResourcePolicies(ctx context.Context, token, realm string, params GetResourcePoliciesParams) ([]*ResourcePolicyRepresentation, error) { const errMessage = "could not get resource policies" queryParams, err := GetQueryParams(params) if err != nil { return nil, err } var result []*ResourcePolicyRepresentation resp, err := g.GetRequestWithBearerAuth(ctx, token). SetResult(&result). SetQueryParams(queryParams). Get(g.getRealmURL(realm, "authz", "protection", "uma-policy")) if err := checkForError(resp, err, errMessage); err != nil { return nil, err } return result, nil } // CreateResourcePolicy associates a permission with a specific resource, using token obtained by Resource Owner Password Credentials Grant or Token exchange func (g *GoCloak) CreateResourcePolicy(ctx context.Context, token, realm, resourceID string, policy ResourcePolicyRepresentation) (*ResourcePolicyRepresentation, error) { const errMessage = "could not create resource policy" var result ResourcePolicyRepresentation resp, err := g.GetRequestWithBearerAuthNoCache(ctx, token). SetResult(&result). SetBody(policy). Post(g.getRealmURL(realm, "authz", "protection", "uma-policy", resourceID)) if err := checkForError(resp, err, errMessage); err != nil { return nil, err } return &result, nil } // UpdateResourcePolicy updates a permission for a specific resource, using token obtained by Resource Owner Password Credentials Grant or Token exchange func (g *GoCloak) UpdateResourcePolicy(ctx context.Context, token, realm, permissionID string, policy ResourcePolicyRepresentation) error { const errMessage = "could not update resource policy" resp, err := g.GetRequestWithBearerAuthNoCache(ctx, token). SetBody(policy). Put(g.getRealmURL(realm, "authz", "protection", "uma-policy", permissionID)) return checkForError(resp, err, errMessage) } // DeleteResourcePolicy deletes a permission for a specific resource, using token obtained by Resource Owner Password Credentials Grant or Token exchange func (g *GoCloak) DeleteResourcePolicy(ctx context.Context, token, realm, permissionID string) error { const errMessage = "could not delete resource policy" resp, err := g.GetRequestWithBearerAuth(ctx, token). Delete(g.getRealmURL(realm, "authz", "protection", "uma-policy", permissionID)) return checkForError(resp, err, errMessage) } // GetPermission returns a client's permission with the given id func (g *GoCloak) GetPermission(ctx context.Context, token, realm, idOfClient, permissionID string) (*PermissionRepresentation, error) { const errMessage = "could not get permission" var result PermissionRepresentation resp, err := g.GetRequestWithBearerAuth(ctx, token). SetResult(&result). Get(g.getAdminRealmURL(realm, "clients", idOfClient, "authz", "resource-server", "permission", permissionID)) if err := checkForError(resp, err, errMessage); err != nil { return nil, err } return &result, nil } // GetDependentPermissions returns a client's permission with the given policy id func (g *GoCloak) GetDependentPermissions(ctx context.Context, token, realm, idOfClient, policyID string) ([]*PermissionRepresentation, error) { const errMessage = "could not get permission" var result []*PermissionRepresentation resp, err := g.GetRequestWithBearerAuth(ctx, token). SetResult(&result). Get(g.getAdminRealmURL(realm, "clients", idOfClient, "authz", "resource-server", "policy", policyID, "dependentPolicies")) if err := checkForError(resp, err, errMessage); err != nil { return nil, err } return result, nil } // GetPermissionResources returns a client's resource attached for the given permission id func (g *GoCloak) GetPermissionResources(ctx context.Context, token, realm, idOfClient, permissionID string) ([]*PermissionResource, error) { const errMessage = "could not get permission resource" var result []*PermissionResource resp, err := g.GetRequestWithBearerAuth(ctx, token). SetResult(&result). Get(g.getAdminRealmURL(realm, "clients", idOfClient, "authz", "resource-server", "permission", permissionID, "resources")) if err := checkForError(resp, err, errMessage); err != nil { return nil, err } return result, nil } // GetPermissionScopes returns a client's scopes configured for the given permission id func (g *GoCloak) GetPermissionScopes(ctx context.Context, token, realm, idOfClient, permissionID string) ([]*PermissionScope, error) { const errMessage = "could not get permission scopes" var result []*PermissionScope resp, err := g.GetRequestWithBearerAuth(ctx, token). SetResult(&result). Get(g.getAdminRealmURL(realm, "clients", idOfClient, "authz", "resource-server", "permission", permissionID, "scopes")) if err := checkForError(resp, err, errMessage); err != nil { return nil, err } return result, nil } // GetPermissions returns permissions associated with the client func (g *GoCloak) GetPermissions(ctx context.Context, token, realm, idOfClient string, params GetPermissionParams) ([]*PermissionRepresentation, error) { const errMessage = "could not get permissions" queryParams, err := GetQueryParams(params) if err != nil { return nil, errors.Wrap(err, errMessage) } path := []string{"clients", idOfClient, "authz", "resource-server", "permission"} if !NilOrEmpty(params.Type) { path = append(path, *params.Type) } var result []*PermissionRepresentation resp, err := g.GetRequestWithBearerAuth(ctx, token). SetResult(&result). SetQueryParams(queryParams). Get(g.getAdminRealmURL(realm, path...)) if err := checkForError(resp, err, errMessage); err != nil { return nil, err } return result, nil } // checkPermissionTicketParams checks that mandatory fields are present func checkPermissionTicketParams(permissions []CreatePermissionTicketParams) error { if len(permissions) == 0 { return errors.New("at least one permission ticket must be requested") } for _, pt := range permissions { if NilOrEmpty(pt.ResourceID) { return errors.New("resourceID required for permission ticket") } if NilOrEmptyArray(pt.ResourceScopes) { return errors.New("at least one resourceScope required for permission ticket") } } return nil } // CreatePermissionTicket creates a permission ticket, using access token from client func (g *GoCloak) CreatePermissionTicket(ctx context.Context, token, realm string, permissions []CreatePermissionTicketParams) (*PermissionTicketResponseRepresentation, error) { const errMessage = "could not create permission ticket" err := checkPermissionTicketParams(permissions) if err != nil { return nil, err } var result PermissionTicketResponseRepresentation resp, err := g.GetRequestWithBearerAuth(ctx, token). SetResult(&result). SetBody(permissions). Post(g.getRealmURL(realm, "authz", "protection", "permission")) if err := checkForError(resp, err, errMessage); err != nil { return nil, err } return &result, nil } // checkPermissionGrantParams checks for mandatory fields func checkPermissionGrantParams(permission PermissionGrantParams) error { if NilOrEmpty(permission.RequesterID) { return errors.New("requesterID required to grant user permission") } if NilOrEmpty(permission.ResourceID) { return errors.New("resourceID required to grant user permission") } if NilOrEmpty(permission.ScopeName) { return errors.New("scopeName required to grant user permission") } return nil } // GrantUserPermission lets resource owner grant permission for specific resource ID to specific user ID func (g *GoCloak) GrantUserPermission(ctx context.Context, token, realm string, permission PermissionGrantParams) (*PermissionGrantResponseRepresentation, error) { const errMessage = "could not grant user permission" err := checkPermissionGrantParams(permission) if err != nil { return nil, err } permission.Granted = BoolP(true) var result PermissionGrantResponseRepresentation resp, err := g.GetRequestWithBearerAuth(ctx, token). SetResult(&result). SetBody(permission). Post(g.getRealmURL(realm, "authz", "protection", "permission", "ticket")) if err := checkForError(resp, err, errMessage); err != nil { return nil, err } return &result, nil } // checkPermissionUpdateParams func checkPermissionUpdateParams(permission PermissionGrantParams) error { err := checkPermissionGrantParams(permission) if err != nil { return err } if permission.Granted == nil { return errors.New("granted required to update user permission") } return nil } // UpdateUserPermission updates user permissions. func (g *GoCloak) UpdateUserPermission(ctx context.Context, token, realm string, permission PermissionGrantParams) (*PermissionGrantResponseRepresentation, error) { const errMessage = "could not update user permission" err := checkPermissionUpdateParams(permission) if err != nil { return nil, err } var result PermissionGrantResponseRepresentation resp, err := g.GetRequestWithBearerAuth(ctx, token). SetResult(&result). SetBody(permission). Put(g.getRealmURL(realm, "authz", "protection", "permission", "ticket")) if err := checkForError(resp, err, errMessage); err != nil { return nil, err } if resp.StatusCode() == http.StatusNoContent { // permission updated to 'not granted' removes permission return nil, nil } return &result, nil } // GetUserPermissions gets granted permissions according query parameters func (g *GoCloak) GetUserPermissions(ctx context.Context, token, realm string, params GetUserPermissionParams) ([]*PermissionGrantResponseRepresentation, error) { const errMessage = "could not get user permissions" queryParams, err := GetQueryParams(params) if err != nil { return nil, err } var result []*PermissionGrantResponseRepresentation resp, err := g.GetRequestWithBearerAuth(ctx, token). SetResult(&result). SetQueryParams(queryParams). Get(g.getRealmURL(realm, "authz", "protection", "permission", "ticket")) if err := checkForError(resp, err, errMessage); err != nil { return nil, err } return result, nil } // DeleteUserPermission revokes permissions according query parameters func (g *GoCloak) DeleteUserPermission(ctx context.Context, token, realm, ticketID string) error { const errMessage = "could not delete user permission" resp, err := g.GetRequestWithBearerAuth(ctx, token). Delete(g.getRealmURL(realm, "authz", "protection", "permission", "ticket", ticketID)) return checkForError(resp, err, errMessage) } // CreatePermission creates a permission associated with the client func (g *GoCloak) CreatePermission(ctx context.Context, token, realm, idOfClient string, permission PermissionRepresentation) (*PermissionRepresentation, error) { const errMessage = "could not create permission" if NilOrEmpty(permission.Type) { return nil, errors.New("type of a permission required") } var result PermissionRepresentation resp, err := g.GetRequestWithBearerAuth(ctx, token). SetResult(&result). SetBody(permission). Post(g.getAdminRealmURL(realm, "clients", idOfClient, "authz", "resource-server", "permission", *(permission.Type))) if err := checkForError(resp, err, errMessage); err != nil { return nil, err } return &result, nil } // UpdatePermission updates a permission associated with the client func (g *GoCloak) UpdatePermission(ctx context.Context, token, realm, idOfClient string, permission PermissionRepresentation) error { const errMessage = "could not update permission" if NilOrEmpty(permission.ID) { return errors.New("ID of a permission required") } resp, err := g.GetRequestWithBearerAuth(ctx, token). SetBody(permission). Put(g.getAdminRealmURL(realm, "clients", idOfClient, "authz", "resource-server", "permission", *permission.Type, *permission.ID)) return checkForError(resp, err, errMessage) } // DeletePermission deletes a policy associated with the client func (g *GoCloak) DeletePermission(ctx context.Context, token, realm, idOfClient, permissionID string) error { const errMessage = "could not delete permission" resp, err := g.GetRequestWithBearerAuth(ctx, token). Delete(g.getAdminRealmURL(realm, "clients", idOfClient, "authz", "resource-server", "permission", permissionID)) return checkForError(resp, err, errMessage) } // --------------- // Credentials API // --------------- // GetCredentialRegistrators returns credentials registrators func (g *GoCloak) GetCredentialRegistrators(ctx context.Context, token, realm string) ([]string, error) { const errMessage = "could not get user credential registrators" var result []string resp, err := g.GetRequestWithBearerAuth(ctx, token). SetResult(&result). Get(g.getAdminRealmURL(realm, "credential-registrators")) if err := checkForError(resp, err, errMessage); err != nil { return nil, err } return result, nil } // GetConfiguredUserStorageCredentialTypes returns credential types, which are provided by the user storage where user is stored func (g *GoCloak) GetConfiguredUserStorageCredentialTypes(ctx context.Context, token, realm, userID string) ([]string, error) { const errMessage = "could not get user credential registrators" var result []string resp, err := g.GetRequestWithBearerAuth(ctx, token). SetResult(&result). Get(g.getAdminRealmURL(realm, "users", userID, "configured-user-storage-credential-types")) if err := checkForError(resp, err, errMessage); err != nil { return nil, err } return result, nil } // GetCredentials returns credentials available for a given user func (g *GoCloak) GetCredentials(ctx context.Context, token, realm, userID string) ([]*CredentialRepresentation, error) { const errMessage = "could not get user credentials" var result []*CredentialRepresentation resp, err := g.GetRequestWithBearerAuth(ctx, token). SetResult(&result). Get(g.getAdminRealmURL(realm, "users", userID, "credentials")) if err := checkForError(resp, err, errMessage); err != nil { return nil, err } return result, nil } // DeleteCredentials deletes the given credential for a given user func (g *GoCloak) DeleteCredentials(ctx context.Context, token, realm, userID, credentialID string) error { const errMessage = "could not delete user credentials" resp, err := g.GetRequestWithBearerAuth(ctx, token). Delete(g.getAdminRealmURL(realm, "users", userID, "credentials", credentialID)) return checkForError(resp, err, errMessage) } // UpdateCredentialUserLabel updates label for the given credential for the given user func (g *GoCloak) UpdateCredentialUserLabel(ctx context.Context, token, realm, userID, credentialID, userLabel string) error { const errMessage = "could not update credential label for a user" resp, err := g.GetRequestWithBearerAuth(ctx, token). SetHeader("Content-Type", "text/plain"). SetBody(userLabel). Put(g.getAdminRealmURL(realm, "users", userID, "credentials", credentialID, "userLabel")) return checkForError(resp, err, errMessage) } // DisableAllCredentialsByType disables all credentials for a user of a specific type func (g *GoCloak) DisableAllCredentialsByType(ctx context.Context, token, realm, userID string, types []string) error { const errMessage = "could not update disable credentials" resp, err := g.GetRequestWithBearerAuth(ctx, token). SetBody(types). Put(g.getAdminRealmURL(realm, "users", userID, "disable-credential-types")) return checkForError(resp, err, errMessage) } // MoveCredentialBehind move a credential to a position behind another credential func (g *GoCloak) MoveCredentialBehind(ctx context.Context, token, realm, userID, credentialID, newPreviousCredentialID string) error { const errMessage = "could not move credential" resp, err := g.GetRequestWithBearerAuth(ctx, token). Post(g.getAdminRealmURL(realm, "users", userID, "credentials", credentialID, "moveAfter", newPreviousCredentialID)) return checkForError(resp, err, errMessage) } // MoveCredentialToFirst move a credential to a first position in the credentials list of the user func (g *GoCloak) MoveCredentialToFirst(ctx context.Context, token, realm, userID, credentialID string) error { const errMessage = "could not move credential" resp, err := g.GetRequestWithBearerAuth(ctx, token). Post(g.getAdminRealmURL(realm, "users", userID, "credentials", credentialID, "moveToFirst")) return checkForError(resp, err, errMessage) } // GetEvents returns events func (g *GoCloak) GetEvents(ctx context.Context, token string, realm string, params GetEventsParams) ([]*EventRepresentation, error) { const errMessage = "could not get events" queryParams, err := GetQueryParams(params) if err != nil { return nil, errors.Wrap(err, errMessage) } var result []*EventRepresentation resp, err := g.GetRequestWithBearerAuth(ctx, token). SetResult(&result). SetQueryParams(queryParams). Get(g.getAdminRealmURL(realm, "events")) if err := checkForError(resp, err, errMessage); err != nil { return nil, err } return result, nil } // GetClientScopesScopeMappingsRealmRolesAvailable returns realm-level roles that are available to attach to this client scope func (g *GoCloak) GetClientScopesScopeMappingsRealmRolesAvailable(ctx context.Context, token, realm, clientScopeID string) ([]*Role, error) { const errMessage = "could not get available realm-level roles with the client-scope" var result []*Role resp, err := g.GetRequestWithBearerAuth(ctx, token). SetResult(&result). Get(g.getAdminRealmURL(realm, "client-scopes", clientScopeID, "scope-mappings", "realm", "available")) if err := checkForError(resp, err, errMessage); err != nil { return nil, err } return result, nil } // GetClientScopesScopeMappingsRealmRoles returns roles associated with a client-scope func (g *GoCloak) GetClientScopesScopeMappingsRealmRoles(ctx context.Context, token, realm, clientScopeID string) ([]*Role, error) { const errMessage = "could not get realm-level roles with the client-scope" var result []*Role resp, err := g.GetRequestWithBearerAuth(ctx, token). SetResult(&result). Get(g.getAdminRealmURL(realm, "client-scopes", clientScopeID, "scope-mappings", "realm")) if err := checkForError(resp, err, errMessage); err != nil { return nil, err } return result, nil } // DeleteClientScopesScopeMappingsRealmRoles deletes realm-level roles from the client-scope func (g *GoCloak) DeleteClientScopesScopeMappingsRealmRoles(ctx context.Context, token, realm, clientScopeID string, roles []Role) error { const errMessage = "could not delete realm-level roles from the client-scope" resp, err := g.GetRequestWithBearerAuth(ctx, token). SetBody(roles). Delete(g.getAdminRealmURL(realm, "client-scopes", clientScopeID, "scope-mappings", "realm")) return checkForError(resp, err, errMessage) } // CreateClientScopesScopeMappingsRealmRoles creates realm-level roles to the client scope func (g *GoCloak) CreateClientScopesScopeMappingsRealmRoles(ctx context.Context, token, realm, clientScopeID string, roles []Role) error { const errMessage = "could not create realm-level roles to the client-scope" resp, err := g.GetRequestWithBearerAuth(ctx, token). SetBody(roles). Post(g.getAdminRealmURL(realm, "client-scopes", clientScopeID, "scope-mappings", "realm")) return checkForError(resp, err, errMessage) } // RegisterRequiredAction creates a required action for a given realm func (g *GoCloak) RegisterRequiredAction(ctx context.Context, token string, realm string, requiredAction RequiredActionProviderRepresentation) error { const errMessage = "could not create required action" resp, err := g.GetRequestWithBearerAuth(ctx, token). SetBody(requiredAction). Post(g.getAdminRealmURL(realm, "authentication", "register-required-action")) if err := checkForError(resp, err, errMessage); err != nil { return err } return err } // GetRequiredActions gets a list of required actions for a given realm func (g *GoCloak) GetRequiredActions(ctx context.Context, token string, realm string) ([]*RequiredActionProviderRepresentation, error) { const errMessage = "could not get required actions" var result []*RequiredActionProviderRepresentation resp, err := g.GetRequestWithBearerAuth(ctx, token). SetResult(&result). Get(g.getAdminRealmURL(realm, "authentication", "required-actions")) if err := checkForError(resp, err, errMessage); err != nil { return nil, err } return result, err } // GetRequiredAction gets a required action for a given realm func (g *GoCloak) GetRequiredAction(ctx context.Context, token string, realm string, alias string) (*RequiredActionProviderRepresentation, error) { const errMessage = "could not get required action" var result RequiredActionProviderRepresentation if alias == "" { return nil, errors.New("alias is required for getting a required action") } resp, err := g.GetRequestWithBearerAuth(ctx, token). SetResult(&result). Get(g.getAdminRealmURL(realm, "authentication", "required-actions", alias)) if err := checkForError(resp, err, errMessage); err != nil { return nil, err } return &result, err } // UpdateRequiredAction updates a required action for a given realm func (g *GoCloak) UpdateRequiredAction(ctx context.Context, token string, realm string, requiredAction RequiredActionProviderRepresentation) error { const errMessage = "could not update required action" if NilOrEmpty(requiredAction.ProviderID) { return errors.New("providerId is required for updating a required action") } resp, err := g.GetRequestWithBearerAuth(ctx, token). SetBody(requiredAction). Put(g.getAdminRealmURL(realm, "authentication", "required-actions", *requiredAction.ProviderID)) return checkForError(resp, err, errMessage) } // DeleteRequiredAction updates a required action for a given realm func (g *GoCloak) DeleteRequiredAction(ctx context.Context, token string, realm string, alias string) error { const errMessage = "could not delete required action" if alias == "" { return errors.New("alias is required for deleting a required action") } resp, err := g.GetRequestWithBearerAuth(ctx, token). Delete(g.getAdminRealmURL(realm, "authentication", "required-actions", alias)) if err := checkForError(resp, err, errMessage); err != nil { return err } return err } // CreateClientScopesScopeMappingsClientRoles attaches a client role to a client scope (not client's scope) func (g *GoCloak) CreateClientScopesScopeMappingsClientRoles( ctx context.Context, token, realm, idOfClientScope, idOfClient string, roles []Role, ) error { const errMessage = "could not create client-level roles to the client-scope" resp, err := g.GetRequestWithBearerAuth(ctx, token). SetBody(roles). Post(g.getAdminRealmURL(realm, "client-scopes", idOfClientScope, "scope-mappings", "clients", idOfClient)) return checkForError(resp, err, errMessage) } // GetClientScopesScopeMappingsClientRolesAvailable returns available (i.e. not attached via // CreateClientScopesScopeMappingsClientRoles) client roles for a specific client, for a client scope // (not client's scope). func (g *GoCloak) GetClientScopesScopeMappingsClientRolesAvailable(ctx context.Context, token, realm, idOfClientScope, idOfClient string) ([]*Role, error) { const errMessage = "could not get available client-level roles with the client-scope" var result []*Role resp, err := g.GetRequestWithBearerAuth(ctx, token). SetResult(&result). Get(g.getAdminRealmURL(realm, "client-scopes", idOfClientScope, "scope-mappings", "clients", idOfClient, "available")) if err := checkForError(resp, err, errMessage); err != nil { return nil, err } return result, nil } // GetClientScopesScopeMappingsClientRoles returns attached client roles for a specific client, for a client scope // (not client's scope). func (g *GoCloak) GetClientScopesScopeMappingsClientRoles(ctx context.Context, token, realm, idOfClientScope, idOfClient string) ([]*Role, error) { const errMessage = "could not get client-level roles with the client-scope" var result []*Role resp, err := g.GetRequestWithBearerAuth(ctx, token). SetResult(&result). Get(g.getAdminRealmURL(realm, "client-scopes", idOfClientScope, "scope-mappings", "clients", idOfClient)) if err := checkForError(resp, err, errMessage); err != nil { return nil, err } return result, nil } // DeleteClientScopesScopeMappingsClientRoles removes attachment of client roles from a client scope // (not client's scope). func (g *GoCloak) DeleteClientScopesScopeMappingsClientRoles(ctx context.Context, token, realm, idOfClientScope, idOfClient string, roles []Role) error { const errMessage = "could not delete client-level roles from the client-scope" resp, err := g.GetRequestWithBearerAuth(ctx, token). SetBody(roles). Delete(g.getAdminRealmURL(realm, "client-scopes", idOfClientScope, "scope-mappings", "clients", idOfClient)) return checkForError(resp, err, errMessage) } // RevokeToken revokes the passed token. The token can either be an access or refresh token. func (g *GoCloak) RevokeToken(ctx context.Context, realm, clientID, clientSecret, refreshToken string) error { const errMessage = "could not revoke token" resp, err := g.GetRequestWithBasicAuth(ctx, clientID, clientSecret). SetFormData(map[string]string{ "client_id": clientID, "client_secret": clientSecret, "token": refreshToken, }). Post(g.getRealmURL(realm, g.Config.revokeEndpoint)) return checkForError(resp, err, errMessage) } // UpdateUsersManagementPermissions updates the management permissions for users func (g *GoCloak) UpdateUsersManagementPermissions(ctx context.Context, accessToken, realm string, managementPermissions ManagementPermissionRepresentation) (*ManagementPermissionRepresentation, error) { const errMessage = "could not update users management permissions" var result ManagementPermissionRepresentation resp, err := g.GetRequestWithBearerAuth(ctx, accessToken). SetResult(&result). SetBody(managementPermissions). Put(g.getAdminRealmURL(realm, "users-management-permissions")) if err := checkForError(resp, err, errMessage); err != nil { return nil, err } return &result, nil } // GetUsersManagementPermissions returns the management permissions for users func (g *GoCloak) GetUsersManagementPermissions(ctx context.Context, accessToken, realm string) (*ManagementPermissionRepresentation, error) { const errMessage = "could not get users management permissions" var result ManagementPermissionRepresentation resp, err := g.GetRequestWithBearerAuth(ctx, accessToken). SetResult(&result). Get(g.getAdminRealmURL(realm, "users-management-permissions")) if err := checkForError(resp, err, errMessage); err != nil { return nil, err } return &result, nil }