diff --git a/README.md b/README.md index 9ab5ee24..6f4d7c09 100644 --- a/README.md +++ b/README.md @@ -280,8 +280,8 @@ type GoCloak interface { ClearUserCache(ctx context.Context, token, realm string) error ClearKeysCache(ctx context.Context, token, realm string) error - GetClientUserSessions(ctx context.Context, token, realm, idOfClient string) ([]*UserSessionRepresentation, error) - GetClientOfflineSessions(ctx context.Context, token, realm, idOfClient string) ([]*UserSessionRepresentation, error) +GetClientUserSessions(ctx context.Context, token, realm, idOfClient string, params ...GetClientUserSessionsParams) ([]*UserSessionRepresentation, error) +GetClientOfflineSessions(ctx context.Context, token, realm, idOfClient string, params ...GetClientUserSessionsParams) ([]*UserSessionRepresentation, error) GetUserSessions(ctx context.Context, token, realm, userID string) ([]*UserSessionRepresentation, error) GetUserOfflineSessionsForClient(ctx context.Context, token, realm, userID, idOfClient string) ([]*UserSessionRepresentation, error) diff --git a/client.go b/client.go index c1853edf..9f06b215 100644 --- a/client.go +++ b/client.go @@ -1451,12 +1451,23 @@ func (g *GoCloak) RegenerateClientSecret(ctx context.Context, token, realm, idOf } // GetClientOfflineSessions returns offline sessions associated with the client -func (g *GoCloak) GetClientOfflineSessions(ctx context.Context, token, realm, idOfClient string) ([]*UserSessionRepresentation, error) { +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 params != nil && 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 { @@ -1467,12 +1478,23 @@ func (g *GoCloak) GetClientOfflineSessions(ctx context.Context, token, realm, id } // GetClientUserSessions returns user sessions associated with the client -func (g *GoCloak) GetClientUserSessions(ctx context.Context, token, realm, idOfClient string) ([]*UserSessionRepresentation, error) { +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 params != nil && 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 { diff --git a/client_test.go b/client_test.go index 3693cf78..9ceebeab 100644 --- a/client_test.go +++ b/client_test.go @@ -3719,14 +3719,52 @@ func Test_GetClientUserSessions(t *testing.T) { ) require.NoError(t, err, "Login failed") token := GetAdminToken(t, client) + allSessionsWithoutParams, err := client.GetClientUserSessions( + context.Background(), + token.AccessToken, + cfg.GoCloak.Realm, + gocloakClientID, + ) + require.NoError(t, err, "GetClientUserSessions failed") + require.NotEmpty(t, allSessionsWithoutParams, "GetClientUserSessions returned an empty list") + + allSessions, err := client.GetClientUserSessions( + context.Background(), + token.AccessToken, + cfg.GoCloak.Realm, + gocloakClientID, + gocloak.GetClientUserSessionsParams{}, + ) + require.NoError(t, err, "GetClientUserSessions failed") + require.NotEmpty(t, allSessions, "GetClientUserSessions returned an empty list") + require.Equal(t, allSessionsWithoutParams, allSessions, + "GetClientUserSessions with and without params are not the same") + sessions, err := client.GetClientUserSessions( context.Background(), token.AccessToken, cfg.GoCloak.Realm, gocloakClientID, + gocloak.GetClientUserSessionsParams{ + Max: gocloak.IntP(1), + }, ) require.NoError(t, err, "GetClientUserSessions failed") - require.NotEmpty(t, sessions, "GetClientUserSessions returned an empty list") + require.Len(t, sessions, 1) + + sessions, err = client.GetClientUserSessions( + context.Background(), + token.AccessToken, + cfg.GoCloak.Realm, + gocloakClientID, + gocloak.GetClientUserSessionsParams{ + Max: gocloak.IntP(1), + First: gocloak.IntP(1), + }, + ) + require.NoError(t, err, "GetClientUserSessions failed") + require.Len(t, sessions, 1) + require.Equal(t, *allSessions[1].ID, *sessions[0].ID) } func findProtocolMapperByID(t *testing.T, client *gocloak.Client, id string) *gocloak.ProtocolMapperRepresentation { @@ -3865,9 +3903,21 @@ func Test_GetClientOfflineSessions(t *testing.T) { token.AccessToken, cfg.GoCloak.Realm, gocloakClientID, + gocloak.GetClientUserSessionsParams{}, + ) + require.NoError(t, err, "GetClientOfflineSessions failed") + require.NotEmpty(t, sessions, "GetClientOfflineSessions returned an empty list") + + sessionsWithoutParams, err := client.GetClientOfflineSessions( + context.Background(), + token.AccessToken, + cfg.GoCloak.Realm, + gocloakClientID, ) require.NoError(t, err, "GetClientOfflineSessions failed") require.NotEmpty(t, sessions, "GetClientOfflineSessions returned an empty list") + require.Equal(t, sessions, sessionsWithoutParams, + "GetClientOfflineSessions with and without params are not the same") } func Test_ClientSecret(t *testing.T) { diff --git a/model_test.go b/model_test.go index ad069f2d..d14acf60 100644 --- a/model_test.go +++ b/model_test.go @@ -335,6 +335,7 @@ func TestStringerOmitEmpty(t *testing.T) { &gocloak.GetClientsParams{}, &gocloak.RequestingPartyTokenOptions{}, &gocloak.RequestingPartyPermission{}, + &gocloak.GetClientUserSessionsParams{}, } for _, custom := range customs { diff --git a/models.go b/models.go index afd2e65e..ee051217 100644 --- a/models.go +++ b/models.go @@ -1416,6 +1416,12 @@ type ManagementPermissionRepresentation struct { ScopePermissions *map[string]string `json:"scopePermissions,omitempty"` } +// GetClientUserSessionsParams represents the optional parameters for getting user sessions associated with the client +type GetClientUserSessionsParams struct { + First *int `json:"first,string,omitempty"` + Max *int `json:"max,string,omitempty"` +} + // prettyStringStruct returns struct formatted into pretty string func prettyStringStruct(t interface{}) string { json, err := json.MarshalIndent(t, "", "\t") @@ -1509,3 +1515,4 @@ func (v *GetResourcePoliciesParams) String() string { return pre func (v *CredentialRepresentation) String() string { return prettyStringStruct(v) } func (v *RequiredActionProviderRepresentation) String() string { return prettyStringStruct(v) } func (v *BruteForceStatus) String() string { return prettyStringStruct(v) } +func (v *GetClientUserSessionsParams) String() string { return prettyStringStruct(v) }