Skip to content
This repository was archived by the owner on Jul 9, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,10 @@ describe('OneAuth Serivce', () => {
id: 'myAccount',
realm: 'myTenant',
};

const tomorrow = Date.now() + 1000 * 60 * 60 * 24;
const mockCredential = {
expiresOn: 9999,
expiresOn: tomorrow,
value: 'someToken',
};
const mockOneAuth = {
Expand Down Expand Up @@ -255,15 +257,19 @@ describe('OneAuth Serivce', () => {
});

it('should get an ARM token for a tenant', async () => {
mockOneAuth.acquireCredentialSilently.mockReturnValueOnce({ credential: { value: 'someARMToken' } });
(oneAuthService as any).signedInARMAccount = {};
mockOneAuth.acquireCredentialSilently.mockReturnValueOnce({
credential: { value: 'someARMToken', expiresOn: tomorrow },
});
(oneAuthService as any).signedInARMAccount = { id: 'someAccount' };
const result = await oneAuthService.getARMTokenForTenant('someTenant');

expect(result).toBe('someARMToken');
});

it('should get an ARM token for a tenant interactively if interaction is required', async () => {
mockOneAuth.acquireCredentialInteractively.mockReturnValueOnce({ credential: { value: 'someARMToken' } });
mockOneAuth.acquireCredentialInteractively.mockReturnValueOnce({
credential: { value: 'someARMToken', expiresOn: tomorrow },
});
mockOneAuth.acquireCredentialSilently.mockRejectedValueOnce({ error: { status: 2 /* Interaction Required */ } });
(oneAuthService as any).signedInARMAccount = {};
const result = await oneAuthService.getARMTokenForTenant('someTenant');
Expand Down
89 changes: 57 additions & 32 deletions Composer/packages/electron-server/src/auth/oneAuthService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,10 @@ export class OneAuthInstance extends OneAuthBase {
private _oneAuth: typeof OneAuth | null = null; //eslint-disable-line
private signedInAccount: OneAuth.Account | undefined;
private signedInARMAccount: OneAuth.Account | undefined;

/** Token solely used to fetch tenants */
private tenantToken: string | undefined;
private tenantTokenExpiresOn: number | undefined;

constructor() {
super();
Expand Down Expand Up @@ -192,13 +194,18 @@ export class OneAuthInstance extends OneAuthBase {
this.initialize();
}

if (!this.signedInARMAccount || !this.tenantToken) {
if (
!this.signedInARMAccount ||
!this.tenantToken ||
(this.tenantTokenExpiresOn && Date.now() >= this.tenantTokenExpiresOn)
) {
// log the user into the infrastructure tenant to get a token that can be used on the "tenants" API
log('Logging user into ARM...');
const signInParams = new this.oneAuth.AuthParameters(DEFAULT_AUTH_SCHEME, ARM_AUTHORITY, ARM_RESOURCE, '', '');
const result: OneAuth.AuthResult = await this.oneAuth.signInInteractively(undefined, signInParams, '');
this.signedInARMAccount = result.account;
this.tenantToken = result.credential.value;
this.tenantTokenExpiresOn = result.credential.expiresOn;
}

// call the tenants API
Expand All @@ -218,47 +225,64 @@ export class OneAuthInstance extends OneAuthBase {
if (!this.initialized) {
this.initialize();
}
// sign in arm account.

// if not signed into the ARM account, sign in.
if (!this.signedInARMAccount) {
const signInParams = new this.oneAuth.AuthParameters(DEFAULT_AUTH_SCHEME, ARM_AUTHORITY, ARM_RESOURCE, '', '');
const result: OneAuth.AuthResult = await this.oneAuth.signInInteractively(undefined, signInParams, '');
if (!result.account) {
return '';
}

this.signedInARMAccount = result.account;
}
if (this.signedInARMAccount) {
try {
log('Getting an ARM token for tenant %s', tenantId);
const tokenParams = new this.oneAuth.AuthParameters(
DEFAULT_AUTH_SCHEME,
`https://login.microsoftonline.com/${tenantId}`,
ARM_RESOURCE,
'',
''
);
const result = await this.oneAuth.acquireCredentialSilently(this.signedInARMAccount.id, tokenParams, '');

// try to get the tenant token silently
try {
log('Getting an ARM token for tenant %s', tenantId);
const tokenParams = new this.oneAuth.AuthParameters(
DEFAULT_AUTH_SCHEME,
`https://login.microsoftonline.com/${tenantId}`,
ARM_RESOURCE,
'',
''
);
const result = await this.oneAuth.acquireCredentialSilently(this.signedInARMAccount.id, tokenParams, '');
if (result.credential.value && Date.now() <= result.credential.expiresOn) {
log('Acquired ARM token for tenant: %s', result.credential.value);
return result.credential.value;
} catch (e) {
if (e.error?.status === Status.InteractionRequired) {
// try again but interactively
log('Acquiring ARM token failed: Interaction required. Trying again interactively to get access token.');
const tokenParams = new this.oneAuth.AuthParameters(
DEFAULT_AUTH_SCHEME,
`https://login.microsoftonline.com/${tenantId}`,
ARM_RESOURCE,
'',
''
);
const result = await this.oneAuth.acquireCredentialInteractively(this.signedInARMAccount.id, tokenParams, '');
if (result.credential && result.credential.value) {
log('Acquired access token interactively. %s', result.credential.value);
return result.credential.value;
}
}
log('There was an error trying to get an ARM token for tenant %s: %O', tenantId, e);
}
} catch (e) {
if (e.error?.status === Status.InteractionRequired) {
log(
'There was an error trying to silently get an ARM token for tenant %s: %O. Trying again interactively to get access token.',
tenantId,
e
);
} else {
throw e;
}
}
return '';

// get the tenant token interactively
try {
const tokenParams = new this.oneAuth.AuthParameters(
DEFAULT_AUTH_SCHEME,
`https://login.microsoftonline.com/${tenantId}`,
ARM_RESOURCE,
'',
''
);
const result = await this.oneAuth.acquireCredentialInteractively(this.signedInARMAccount.id, tokenParams, '');
if (!result.credential.value) {
throw new Error('Interactive sign on returned an empty credential value.');
}
log('Acquired ARM token for tenant: %s', result.credential.value);
return result.credential.value;
} catch (e) {
log('There was an error trying to get an ARM token interactively for tenant %s: %O', tenantId, e);
throw e;
}
}

public shutdown() {
Expand All @@ -275,6 +299,7 @@ export class OneAuthInstance extends OneAuthBase {
this.signedInAccount = undefined;
this.signedInARMAccount = undefined;
this.tenantToken = undefined;
this.tenantTokenExpiresOn = undefined;
log('Signed out user.');
}

Expand Down