Skip to content

Commit

Permalink
New command: Revoke Sign-in Sessions
Browse files Browse the repository at this point in the history
  • Loading branch information
MartinM85 committed Jan 13, 2025
1 parent f1553f6 commit 6dfbf6c
Show file tree
Hide file tree
Showing 3 changed files with 11 additions and 53 deletions.
44 changes: 2 additions & 42 deletions docs/docs/cmd/entra/user/user-session-revoke.mdx
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
import Global from '/docs/cmd/_global.mdx';
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

# entra user session revoke

Expand Down Expand Up @@ -30,7 +28,7 @@ m365 entra user session revoke [options]

:::info

The user with at least User Administrator role can revoke sign-in sessions of other users.
To use this command you must be either **User Administrator** or **Global Administrator**.

:::

Expand Down Expand Up @@ -64,42 +62,4 @@ m365 entra user session revoke --userName [email protected] --for

## Response

<Tabs>
<TabItem value="JSON">

```json
{
"value": true
}
```

</TabItem>
<TabItem value="Text">

```text
value: true
```

</TabItem>
<TabItem value="CSV">

```csv
value
1
```

</TabItem>
<TabItem value="Markdown">

```md
# entra user session revoke --userName "[email protected]" --force "true"

Date: 1/5/2025

Property | Value
---------|-------
value | true
```

</TabItem>
</Tabs>
The command won't return a response on success.
11 changes: 5 additions & 6 deletions src/m365/entra/commands/user/user-session-revoke.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,14 @@ import { CommandError } from '../../../../Command.js';
import { z } from 'zod';
import { CommandInfo } from '../../../../cli/CommandInfo.js';
import { cli } from '../../../../cli/cli.js';
import { formatting } from '../../../../utils/formatting.js';

describe(commands.USER_SESSION_REVOKE, () => {
const userId = 'abcd1234-de71-4623-b4af-96380a352509';
const userName = '[email protected]';

let log: string[];
let logger: Logger;
let loggerLogSpy: sinon.SinonSpy;
let promptIssued: boolean;
let commandInfo: CommandInfo;
let commandOptionsSchema: z.ZodTypeAny;
Expand Down Expand Up @@ -53,7 +53,6 @@ describe(commands.USER_SESSION_REVOKE, () => {
return false;
});
promptIssued = false;
loggerLogSpy = sinon.spy(logger, 'log');
});

afterEach(() => {
Expand Down Expand Up @@ -119,8 +118,8 @@ describe(commands.USER_SESSION_REVOKE, () => {
});

it('revokes all sign-in sessions for a user specified by userId without prompting for confirmation', async () => {
sinon.stub(request, 'post').callsFake(async (opts) => {
if (opts.url === `https://graph.microsoft.com/v1.0/users('${userId}')/revokeSignInSessions`) {
const postStub = sinon.stub(request, 'post').callsFake(async (opts) => {
if (opts.url === `https://graph.microsoft.com/v1.0/users('${formatting.encodeQueryParameter(userId)}')/revokeSignInSessions`) {
return {
value: true
};
Expand All @@ -131,12 +130,12 @@ describe(commands.USER_SESSION_REVOKE, () => {

const parsedSchema = commandOptionsSchema.safeParse({ userId: userId, force: true, verbose: true });
await command.action(logger, { options: parsedSchema.data });
assert(loggerLogSpy.calledOnceWith({ value: true }));
assert(postStub.calledOnce);
});

it('revokes all sign-in sessions for a user specified by UPN while prompting for confirmation', async () => {
const postRequestStub = sinon.stub(request, 'post').callsFake(async (opts) => {
if (opts.url === `https://graph.microsoft.com/v1.0/users('${userName}')/revokeSignInSessions`) {
if (opts.url === `https://graph.microsoft.com/v1.0/users('${formatting.encodeQueryParameter(userName)}')/revokeSignInSessions`) {
return {
value: true
};
Expand Down
9 changes: 4 additions & 5 deletions src/m365/entra/commands/user/user-session-revoke.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { validation } from '../../../../utils/validation.js';
import { Logger } from '../../../../cli/Logger.js';
import request, { CliRequestOptions } from '../../../../request.js';
import { cli } from '../../../../cli/cli.js';
import { formatting } from '../../../../utils/formatting.js';

const options = globalOptionsZod
.extend({
Expand Down Expand Up @@ -39,7 +40,7 @@ class EntraUserSessionRevokeCommand extends GraphCommand {
public getRefinedSchema(schema: typeof options): z.ZodEffects<any> | undefined {
return schema
.refine(options => [options.userId, options.userName].filter(o => o !== undefined).length === 1, {
message: 'Specify either userId or userName'
message: `Specify either 'userId' or 'userName'.`
});
}
public async commandAction(logger: Logger, args: CommandArgs): Promise<void> {
Expand All @@ -52,17 +53,15 @@ class EntraUserSessionRevokeCommand extends GraphCommand {
}

const requestOptions: CliRequestOptions = {
url: `${this.resource}/v1.0/users('${userIdentifier}')/revokeSignInSessions`,
url: `${this.resource}/v1.0/users('${formatting.encodeQueryParameter(userIdentifier!)}')/revokeSignInSessions`,
headers: {
accept: 'application/json;odata.metadata=none'
},
responseType: 'json',
data: {}
};

const result = await request.post(requestOptions);

await logger.log(result);
await request.post(requestOptions);
}
catch (err: any) {
this.handleRejectedODataJsonPromise(err);
Expand Down

0 comments on commit 6dfbf6c

Please sign in to comment.