From 777a4facbc0ee80ba9af84775f3e26875537a2d6 Mon Sep 17 00:00:00 2001 From: Gyanesh Gouraw <160731216+gyaneshgouraw-okta@users.noreply.github.com> Date: Mon, 15 Jul 2024 12:23:31 +0530 Subject: [PATCH] Added support for users getSessions & getRefreshTokens endpoint in management api client (#1021) Co-authored-by: gyaneshgouraw-okta --- .../__generated/managers/users-manager.ts | 142 +++++++++ src/management/__generated/models/index.ts | 284 ++++++++++++++++++ test/management/users.test.ts | 188 ++++++++++++ 3 files changed, 614 insertions(+) diff --git a/src/management/__generated/managers/users-manager.ts b/src/management/__generated/managers/users-manager.ts index 85b82fff9..e44f44e53 100644 --- a/src/management/__generated/managers/users-manager.ts +++ b/src/management/__generated/managers/users-manager.ts @@ -9,6 +9,8 @@ import type { GetLogs200Response, GetOrganizationMemberRoles200Response, GetPermissions200Response, + GetRefreshTokensForUser200Response, + GetSessionsForUser200Response, GetUserOrganizations200Response, GetUsers200Response, GetUsers200ResponseOneOfInner, @@ -40,6 +42,8 @@ import type { DeleteAuthenticatorsRequest, DeleteMultifactorByProviderRequest, DeletePermissionsOperationRequest, + DeleteRefreshTokensForUserRequest, + DeleteSessionsForUserRequest, DeleteUserIdentityByUserIdRequest, DeleteUserRolesOperationRequest, DeleteUsersByIdRequest, @@ -48,6 +52,8 @@ import type { GetEnrollmentsRequest, GetLogsByUserRequest, GetPermissionsRequest, + GetRefreshTokensForUserRequest, + GetSessionsForUserRequest, GetUserOrganizationsRequest, GetUserRolesRequest, GetUsersRequest, @@ -205,6 +211,58 @@ export class UsersManager extends BaseAPI { return runtime.VoidApiResponse.fromResponse(response); } + /** + * Delete all refresh tokens for a user. + * Delete refresh tokens for a user + * + * @throws {RequiredError} + */ + async deleteRefreshTokens( + requestParameters: DeleteRefreshTokensForUserRequest, + initOverrides?: InitOverride + ): Promise> { + runtime.validateRequiredRequestParams(requestParameters, ['user_id']); + + const response = await this.request( + { + path: `/users/{user_id}/refresh-tokens`.replace( + '{user_id}', + encodeURIComponent(String(requestParameters.user_id)) + ), + method: 'DELETE', + }, + initOverrides + ); + + return runtime.VoidApiResponse.fromResponse(response); + } + + /** + * Delete all sessions for a user. + * Delete sessions for user + * + * @throws {RequiredError} + */ + async deleteSessions( + requestParameters: DeleteSessionsForUserRequest, + initOverrides?: InitOverride + ): Promise> { + runtime.validateRequiredRequestParams(requestParameters, ['user_id']); + + const response = await this.request( + { + path: `/users/{user_id}/sessions`.replace( + '{user_id}', + encodeURIComponent(String(requestParameters.user_id)) + ), + method: 'DELETE', + }, + initOverrides + ); + + return runtime.VoidApiResponse.fromResponse(response); + } + /** * Unlink an identity from the target user making it a separate user account again. * Unlink a User Identity @@ -493,6 +551,90 @@ export class UsersManager extends BaseAPI { return runtime.JSONApiResponse.fromResponse(response); } + /** + * Retrieve details for a user's refresh tokens. + * Get refresh tokens for a user + * + * @throws {RequiredError} + */ + async getRefreshTokens( + requestParameters: GetRefreshTokensForUserRequest, + initOverrides?: InitOverride + ): Promise> { + runtime.validateRequiredRequestParams(requestParameters, ['user_id']); + + const queryParameters = runtime.applyQueryParams(requestParameters, [ + { + key: 'include_totals', + config: {}, + }, + { + key: 'from', + config: {}, + }, + { + key: 'take', + config: {}, + }, + ]); + + const response = await this.request( + { + path: `/users/{user_id}/refresh-tokens`.replace( + '{user_id}', + encodeURIComponent(String(requestParameters.user_id)) + ), + method: 'GET', + query: queryParameters, + }, + initOverrides + ); + + return runtime.JSONApiResponse.fromResponse(response); + } + + /** + * Retrieve details for a user's sessions. + * Get sessions for user + * + * @throws {RequiredError} + */ + async getSessions( + requestParameters: GetSessionsForUserRequest, + initOverrides?: InitOverride + ): Promise> { + runtime.validateRequiredRequestParams(requestParameters, ['user_id']); + + const queryParameters = runtime.applyQueryParams(requestParameters, [ + { + key: 'include_totals', + config: {}, + }, + { + key: 'from', + config: {}, + }, + { + key: 'take', + config: {}, + }, + ]); + + const response = await this.request( + { + path: `/users/{user_id}/sessions`.replace( + '{user_id}', + encodeURIComponent(String(requestParameters.user_id)) + ), + method: 'GET', + query: queryParameters, + }, + initOverrides + ); + + return runtime.JSONApiResponse.fromResponse(response); + } + /** * This endpoint will retrieve all organizations that the specified user is a member of. * diff --git a/src/management/__generated/models/index.ts b/src/management/__generated/models/index.ts index d53eacd0d..867ebd26b 100644 --- a/src/management/__generated/models/index.ts +++ b/src/management/__generated/models/index.ts @@ -6344,6 +6344,78 @@ export interface GetRefreshToken200ResponseResourceServersInner { */ scopes: string; } +/** + * + */ +export interface GetRefreshTokensForUser200Response { + [key: string]: any | any; + /** + */ + sessions: Array; +} +/** + * + */ +export interface GetRefreshTokensForUser200ResponseSessionsInner { + [key: string]: any | any; + /** + * The ID of the refresh token + * + */ + id: string; + /** + * ID of the user which can be used when interacting with other APIs. + * + */ + user_id: string; + /** + */ + created_at: GetRefreshTokensForUser200ResponseSessionsInnerCreatedAt; + /** + */ + idle_expires_at: GetRefreshTokensForUser200ResponseSessionsInnerIdleExpiresAt; + /** + */ + expires_at: GetRefreshTokensForUser200ResponseSessionsInnerExpiresAt; + /** + * ID of the client application granted with this refresh token + * + */ + client_id: string; + /** + * ID of the authenticated session used to obtain this refresh-token + * + */ + session_id: string; + /** + * True if the token is a rotating refresh token + * + */ + rotating: boolean; + /** + * A list of the resource server IDs associated to this refresh-token and their granted scopes + * + */ + resource_servers: Array; +} +/** + * + */ +export type GetRefreshTokensForUser200ResponseSessionsInnerCreatedAt = + | string + | { [key: string]: any }; +/** + * + */ +export type GetRefreshTokensForUser200ResponseSessionsInnerExpiresAt = + | string + | { [key: string]: any }; +/** + * + */ +export type GetRefreshTokensForUser200ResponseSessionsInnerIdleExpiresAt = + | string + | { [key: string]: any }; /** * */ @@ -6712,6 +6784,148 @@ export type GetSession200ResponseIdleExpiresAt = string | { [key: string]: any } * */ export type GetSession200ResponseUpdatedAt = string | { [key: string]: any }; +/** + * + */ +export interface GetSessionsForUser200Response { + [key: string]: any | any; + /** + */ + sessions: Array; +} +/** + * + */ +export interface GetSessionsForUser200ResponseSessionsInner { + [key: string]: any | any; + /** + * The ID of the session + * + */ + id: string; + /** + * ID of the user which can be used when interacting with other APIs. + * + */ + user_id: string; + /** + */ + created_at: GetSessionsForUser200ResponseSessionsInnerCreatedAt; + /** + */ + updated_at: GetSessionsForUser200ResponseSessionsInnerUpdatedAt; + /** + */ + authenticated_at: GetSessionsForUser200ResponseSessionsInnerAuthenticatedAt; + /** + */ + idle_expires_at: GetSessionsForUser200ResponseSessionsInnerIdleExpiresAt; + /** + */ + expires_at: GetSessionsForUser200ResponseSessionsInnerExpiresAt; + /** + */ + device: GetSessionsForUser200ResponseSessionsInnerDevice; + /** + * List of client details for the session + * + */ + clients: Array; + /** + */ + authentication: GetSessionsForUser200ResponseSessionsInnerAuthentication; +} +/** + * + */ +export type GetSessionsForUser200ResponseSessionsInnerAuthenticatedAt = + | string + | { [key: string]: any }; +/** + * Details about authentication signals obtained during the login flow + */ +export interface GetSessionsForUser200ResponseSessionsInnerAuthentication { + [key: string]: any | any; + /** + * Contains the authentication methods a user has completed during their session + * + */ + methods: Array; +} +/** + * Authentication signal details + */ +export interface GetSessionsForUser200ResponseSessionsInnerAuthenticationMethodsInner { + [key: string]: any | any; + /** + * One of: "federated", "passkey", "pwd", "sms", "email", "mfa", "mock" or a custom method denoted by a URL + * + */ + name: string; + /** + */ + timestamp: GetSessionsForUser200ResponseSessionsInnerAuthenticationMethodsInnerTimestamp; + /** + * A specific MFA factor. Only present when "name" is set to "mfa" + * + */ + type$: string; +} +/** + * + */ +export type GetSessionsForUser200ResponseSessionsInnerAuthenticationMethodsInnerTimestamp = + | string + | { [key: string]: any }; +/** + * + */ +export type GetSessionsForUser200ResponseSessionsInnerCreatedAt = string | { [key: string]: any }; +/** + * Metadata related to the device used in the session + */ +export interface GetSessionsForUser200ResponseSessionsInnerDevice { + [key: string]: any | any; + /** + * First IP address associated with this session + * + */ + initial_ip: string; + /** + * First autonomous system number associated with this session + * + */ + initial_asn: string; + /** + * Last user agent of the device from which this user logged in + * + */ + last_user_agent: string; + /** + * Last IP address from which this user logged in + * + */ + last_ip: string; + /** + * Last autonomous system number from which this user logged in + * + */ + last_asn: string; +} +/** + * + */ +export type GetSessionsForUser200ResponseSessionsInnerExpiresAt = string | { [key: string]: any }; +/** + * + */ +export type GetSessionsForUser200ResponseSessionsInnerIdleExpiresAt = + | string + | { [key: string]: any }; +/** + * + */ +export type GetSessionsForUser200ResponseSessionsInnerUpdatedAt = string | { [key: string]: any }; /** * */ @@ -14937,6 +15151,26 @@ export interface DeletePermissionsOperationRequest { */ id: string; } +/** + * + */ +export interface DeleteRefreshTokensForUserRequest { + /** + * ID of the user to get remove refresh tokens for + * + */ + user_id: string; +} +/** + * + */ +export interface DeleteSessionsForUserRequest { + /** + * ID of the user to get sessions for + * + */ + user_id: string; +} /** * @@ -15152,6 +15386,56 @@ export interface GetPermissionsRequest { */ include_totals?: boolean; } +/** + * + */ +export interface GetRefreshTokensForUserRequest { + /** + * ID of the user to get refresh tokens for + * + */ + user_id: string; + /** + * Return results inside an object that contains the total result count (true) or as a direct array of results (false, default). + * + */ + include_totals?: boolean; + /** + * Optional token ID from which to start selection (exclusive). + * + */ + from?: string; + /** + * Number of results per page. Defaults to 50. + * + */ + take?: number; +} +/** + * + */ +export interface GetSessionsForUserRequest { + /** + * ID of the user to get sessions for + * + */ + user_id: string; + /** + * Return results inside an object that contains the total result count (true) or as a direct array of results (false, default). + * + */ + include_totals?: boolean; + /** + * Optional session ID from which to start selection (exclusive). + * + */ + from?: string; + /** + * Number of results per page. Defaults to 50. + * + */ + take?: number; +} /** * */ diff --git a/test/management/users.test.ts b/test/management/users.test.ts index fba13d72c..ecb67afeb 100644 --- a/test/management/users.test.ts +++ b/test/management/users.test.ts @@ -1384,4 +1384,192 @@ describe('UsersManager', () => { expect(scope.isDone()).toBe(true); }); }); + + describe('#getSessions', () => { + const data = { + id: '5', + name: 'Test rule', + enabled: true, + script: "function (user, contest, callback) { console.log('Test'); }", + stage: 'login_success', + }; + let scope: nock.Scope; + + beforeEach(() => { + scope = nock(API_URL).get(`/users/${data.id}/sessions`).reply(200, data); + }); + + it('should return a promise if no callback is given', (done) => { + expect(usersManager.getSessions({ user_id: data.id }).then(() => done())).toBeInstanceOf( + Promise + ); + }); + + it('should perform a POST request to /api/v2/users/5', async () => { + await usersManager.getSessions({ user_id: data.id }); + expect(scope.isDone()).toBe(true); + }); + + it('should pass any errors to the promise catch handler', async () => { + nock.cleanAll(); + + nock(API_URL).get(`/users/${data.id}/sessions`).reply(500, {}); + + try { + await usersManager.getSessions({ user_id: data.id }); + } catch (err) { + expect(err).toBeDefined(); + } + }); + + it('should include the token in the Authorization header', async () => { + nock.cleanAll(); + + const request = nock(API_URL) + .get(`/users/${data.id}/sessions`) + .matchHeader('Authorization', `Bearer ${token}`) + .reply(200, []); + + await usersManager.getSessions({ user_id: data.id }); + expect(request.isDone()).toBe(true); + }); + }); + + describe('#deleteSessions', () => { + const id = 'USER_5'; + let scope: nock.Scope; + + beforeEach(() => { + scope = nock(API_URL).delete(`/users/${id}/sessions`).reply(200, {}); + }); + + it('should return a promise when no callback is given', (done) => { + expect(usersManager.deleteSessions({ user_id: id }).then(() => done())).toBeInstanceOf( + Promise + ); + }); + + it(`should perform a delete request to /users/${id}`, async () => { + await usersManager.deleteSessions({ user_id: id }); + expect(scope.isDone()).toBe(true); + }); + + it('should pass any errors to the promise catch handler', async () => { + nock.cleanAll(); + + nock(API_URL).delete(`/users/${id}`).reply(500, {}); + + try { + await usersManager.deleteSessions({ user_id: id }); + } catch (err) { + expect(err).toBeDefined(); + } + }); + + it('should include the token in the authorization header', async () => { + nock.cleanAll(); + + const request = nock(API_URL) + .delete(`/users/${id}/sessions`) + .matchHeader('authorization', `Bearer ${token}`) + .reply(200, {}); + + await usersManager.deleteSessions({ user_id: id }); + expect(request.isDone()).toBe(true); + }); + }); + + describe('#getRefreshTokens', () => { + const data = { + id: '5', + name: 'Test rule', + enabled: true, + script: "function (user, contest, callback) { console.log('Test'); }", + stage: 'login_success', + }; + let scope: nock.Scope; + + beforeEach(() => { + scope = nock(API_URL).get(`/users/${data.id}/refresh-tokens`).reply(200, data); + }); + + it('should return a promise if no callback is given', (done) => { + expect(usersManager.getRefreshTokens({ user_id: data.id }).then(() => done())).toBeInstanceOf( + Promise + ); + }); + + it('should perform a POST request to /api/v2/users/5', async () => { + await usersManager.getRefreshTokens({ user_id: data.id }); + expect(scope.isDone()).toBe(true); + }); + + it('should pass any errors to the promise catch handler', async () => { + nock.cleanAll(); + + nock(API_URL).get(`/users/${data.id}/refresh-tokens`).reply(500, {}); + + try { + await usersManager.getRefreshTokens({ user_id: data.id }); + } catch (err) { + expect(err).toBeDefined(); + } + }); + + it('should include the token in the Authorization header', async () => { + nock.cleanAll(); + + const request = nock(API_URL) + .get(`/users/${data.id}/refresh-tokens`) + .matchHeader('Authorization', `Bearer ${token}`) + .reply(200, []); + + await usersManager.getRefreshTokens({ user_id: data.id }); + expect(request.isDone()).toBe(true); + }); + }); + + describe('#deleteRefreshTokens', () => { + const id = 'USER_5'; + let scope: nock.Scope; + + beforeEach(() => { + scope = nock(API_URL).delete(`/users/${id}/refresh-tokens`).reply(200, {}); + }); + + it('should return a promise when no callback is given', (done) => { + expect(usersManager.deleteRefreshTokens({ user_id: id }).then(() => done())).toBeInstanceOf( + Promise + ); + }); + + it(`should perform a delete request to /users/${id}`, async () => { + await usersManager.deleteRefreshTokens({ user_id: id }); + expect(scope.isDone()).toBe(true); + }); + + it('should pass any errors to the promise catch handler', async () => { + nock.cleanAll(); + + nock(API_URL).delete(`/users/${id}`).reply(500, {}); + + try { + await usersManager.deleteRefreshTokens({ user_id: id }); + } catch (err) { + expect(err).toBeDefined(); + } + }); + + it('should include the token in the authorization header', async () => { + nock.cleanAll(); + + const request = nock(API_URL) + .delete(`/users/${id}/refresh-tokens`) + .matchHeader('authorization', `Bearer ${token}`) + .reply(200, {}); + + await usersManager.deleteRefreshTokens({ user_id: id }); + expect(request.isDone()).toBe(true); + }); + }); });