Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[rc4] Use public client auth for odsp e2e flows (#21091) #21106

Merged
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 @@ -23,7 +23,6 @@ export interface IOdspLoginCredentials {
*/
export interface IOdspCredentials extends IOdspLoginCredentials {
clientId: string;
clientSecret: string;
}

/**
Expand All @@ -38,7 +37,6 @@ export function createOdspClient(
const siteUrl = process.env.odsp__client__siteUrl as string;
const driveId = process.env.odsp__client__driveId as string;
const clientId = process.env.odsp__client__clientId as string;
const clientSecret = process.env.odsp__client__clientSecret as string;
if (siteUrl === "" || siteUrl === undefined) {
throw new Error("site url is missing");
}
Expand All @@ -50,17 +48,12 @@ export function createOdspClient(
throw new Error("client id is missing");
}

if (clientSecret === "" || clientSecret === undefined) {
throw new Error("client secret is missing");
}

if (creds.username === undefined || creds.password === undefined) {
throw new Error("username or password is missing for login account");
}

const credentials: IOdspCredentials = {
clientId,
clientSecret,
...creds,
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

import { IOdspTokenProvider } from "@fluid-experimental/odsp-client";
import {
IClientConfig,
IPublicClientConfig,
TokenRequestCredentials,
getFetchTokenUrl,
unauthPostAsync,
Expand Down Expand Up @@ -53,9 +53,8 @@ export class OdspTestTokenProvider implements IOdspTokenProvider {
refreshToken: string;
}> {
const server = new URL(siteUrl).host;
const clientConfig: IClientConfig = {
const clientConfig: IPublicClientConfig = {
clientId: this.creds.clientId,
clientSecret: this.creds.clientSecret,
};
const credentials: TokenRequestCredentials = {
grant_type: "password",
Expand All @@ -65,7 +64,6 @@ export class OdspTestTokenProvider implements IOdspTokenProvider {
const body = {
scope,
client_id: clientConfig.clientId,
client_secret: clientConfig.clientSecret,
...credentials,
};
const response = await unauthPostAsync(getFetchTokenUrl(server), new URLSearchParams(body));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ import { OdspTestTokenProvider } from "./odspTestTokenProvider.js";
*/
export interface OdspTestCredentials {
clientId: string;
clientSecret: string;
username: string;
password: string;
}
Expand All @@ -33,7 +32,6 @@ export interface OdspTestCredentials {
*/
const clientCreds: OdspTestCredentials = {
clientId: "<client_id>",
clientSecret: "<client_secret>",
username: "<email_id>",
password: "<password>",
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

import { assert } from "@fluidframework/core-utils/internal";
import {
IClientConfig,
IPublicClientConfig,
TokenRequestCredentials,
getFetchTokenUrl,
unauthPostAsync,
Expand Down Expand Up @@ -52,9 +52,8 @@ export class OdspTestTokenProvider implements IOdspTokenProvider {
refreshToken?: string;
}> {
const server = new URL(siteUrl).host;
const clientConfig: IClientConfig = {
const clientConfig: IPublicClientConfig = {
clientId: this.creds.clientId,
clientSecret: this.creds.clientSecret,
};
const credentials: TokenRequestCredentials = {
grant_type: "password",
Expand All @@ -64,7 +63,6 @@ export class OdspTestTokenProvider implements IOdspTokenProvider {
const body = {
scope,
client_id: clientConfig.clientId,
client_secret: clientConfig.clientSecret,
...credentials,
};
const response = await unauthPostAsync(getFetchTokenUrl(server), new URLSearchParams(body));
Expand Down
6 changes: 3 additions & 3 deletions packages/test/test-drivers/src/odspTestDriver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { ITestDriver, OdspEndpoint } from "@fluid-internal/test-driver-definitio
import { IRequest } from "@fluidframework/core-interfaces";
import { IDocumentServiceFactory, IUrlResolver } from "@fluidframework/driver-definitions/internal";
import {
IClientConfig,
IPublicClientConfig,
getDriveId,
getDriveItemByRootFileName,
} from "@fluidframework/odsp-doclib-utils/internal";
Expand Down Expand Up @@ -41,7 +41,7 @@ interface IOdspTestLoginInfo {
supportsBrowserAuth?: boolean;
}

type TokenConfig = IOdspTestLoginInfo & IClientConfig;
type TokenConfig = IOdspTestLoginInfo & IPublicClientConfig;

interface IOdspTestDriverConfig extends TokenConfig {
directory: string;
Expand Down Expand Up @@ -265,7 +265,7 @@ export class OdspTestDriver implements ITestDriver {

private static async getStorageToken(
options: OdspResourceTokenFetchOptions & { useBrowserAuth?: boolean },
config: IOdspTestLoginInfo & IClientConfig,
config: IOdspTestLoginInfo & IPublicClientConfig,
) {
const host = new URL(options.siteUrl).host;

Expand Down
1 change: 0 additions & 1 deletion packages/test/test-service-load/runLoadTestOnAks.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,6 @@ function CreateInfra {
FLUID_TEST_UID="$TestUid" `
TEST_PROFILE="$TestProfile" `
login__microsoft__clientId="$env:ClientId" `
login__microsoft__secret="$env:ClientSecret" `
APPINSIGHTS_INSTRUMENTATIONKEY="$env:InstrumentationKey" `
BUILD_BUILD_ID="$TestDocFolder"

Expand Down
2 changes: 1 addition & 1 deletion packages/tools/fetch-tool/README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# @fluid-tools/fetch-tool

Connection using ODSP or routerlicious driver to dump the messages or snapshot information on the server.
In order to connect to ODSP, the clientID and clientSecret must be set as environment variables `login__microsoft__clientId` and `login__microsoft__secret`, respectively. If you have access to the keyvault this can be done by running [this tool](../../../tools/getkeys).
In order to connect to ODSP, the clientID must be set as the environment variable `login__microsoft__clientId`. If you have access to the keyvault this can be done by running [this tool](../../../tools/getkeys).
Beware that to use fetch-tool on documents in the Microsoft tenant, you will need to follow the fetch tool usage instructions on the "Debugging Tools" page of the internal Fluid wiki.

## Usage
Expand Down
7 changes: 5 additions & 2 deletions packages/tools/fetch-tool/src/fluidFetchInit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@

import { IRequest } from "@fluidframework/core-interfaces";
import { IResolvedUrl } from "@fluidframework/driver-definitions/internal";
import { IClientConfig, IOdspAuthRequestInfo } from "@fluidframework/odsp-doclib-utils/internal";
import {
IPublicClientConfig,
IOdspAuthRequestInfo,
} from "@fluidframework/odsp-doclib-utils/internal";
import * as odsp from "@fluidframework/odsp-driver/internal";
import {
IOdspResolvedUrl,
Expand All @@ -28,7 +31,7 @@ export let connectionInfo: any;
async function initializeODSPCore(
odspResolvedUrl: IOdspResolvedUrl,
server: string,
clientConfig: IClientConfig,
clientConfig: IPublicClientConfig,
) {
const { driveId, itemId } = odspResolvedUrl;

Expand Down
8 changes: 4 additions & 4 deletions packages/tools/fetch-tool/src/fluidFetchSharePoint.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import child_process from "child_process";

import { DriverErrorTypes } from "@fluidframework/driver-definitions/internal";
import {
IClientConfig,
IPublicClientConfig,
IOdspAuthRequestInfo,
IOdspDriveItem,
getChildrenByDriveItem,
Expand All @@ -28,7 +28,7 @@ import { getForceTokenReauth } from "./fluidFetchArgs.js";
export async function resolveWrapper<T>(
callback: (authRequestInfo: IOdspAuthRequestInfo) => Promise<T>,
server: string,
clientConfig: IClientConfig,
clientConfig: IPublicClientConfig,
forceTokenReauth = false,
forToken = false,
): Promise<T> {
Expand Down Expand Up @@ -72,7 +72,7 @@ export async function resolveWrapper<T>(
async function resolveDriveItemByServerRelativePath(
server: string,
serverRelativePath: string,
clientConfig: IClientConfig,
clientConfig: IPublicClientConfig,
) {
return resolveWrapper<IOdspDriveItem>(
// eslint-disable-next-line @typescript-eslint/promise-function-async
Expand All @@ -86,7 +86,7 @@ async function resolveDriveItemByServerRelativePath(
async function resolveChildrenByDriveItem(
server: string,
folderDriveItem: IOdspDriveItem,
clientConfig: IClientConfig,
clientConfig: IPublicClientConfig,
) {
return resolveWrapper<IOdspDriveItem[]>(
// eslint-disable-next-line @typescript-eslint/promise-function-async
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export function enrichOdspError(error: IFluidErrorBase & OdspError, response?: R
export const fetchIncorrectResponse = 712;

// @internal
export function fetchTokens(server: string, scope: string, clientConfig: IClientConfig, credentials: TokenRequestCredentials): Promise<IOdspTokens>;
export function fetchTokens(server: string, scope: string, clientConfig: IPublicClientConfig, credentials: TokenRequestCredentials): Promise<IOdspTokens>;

// @internal (undocumented)
export function getAadTenant(server: string): string;
Expand Down Expand Up @@ -54,19 +54,19 @@ export function getDriveItemFromDriveAndItem(server: string, drive: string, item
export function getFetchTokenUrl(server: string): string;

// @internal (undocumented)
export function getLoginPageUrl(server: string, clientConfig: IClientConfig, scope: string, odspAuthRedirectUri: string): string;
export function getLoginPageUrl(server: string, clientConfig: IPublicClientConfig, scope: string, odspAuthRedirectUri: string): string;

// @internal (undocumented)
export const getOdspRefreshTokenFn: (server: string, clientConfig: IClientConfig, tokens: IOdspTokens) => () => Promise<string>;
export const getOdspRefreshTokenFn: (server: string, clientConfig: IPublicClientConfig, tokens: IOdspTokens) => () => Promise<string>;

// @alpha (undocumented)
export const getOdspScope: (server: string) => string;

// @internal (undocumented)
export const getPushRefreshTokenFn: (server: string, clientConfig: IClientConfig, tokens: IOdspTokens) => () => Promise<string>;
export const getPushRefreshTokenFn: (server: string, clientConfig: IPublicClientConfig, tokens: IOdspTokens) => () => Promise<string>;

// @internal (undocumented)
export const getRefreshTokenFn: (scope: string, server: string, clientConfig: IClientConfig, tokens: IOdspTokens) => () => Promise<string>;
export const getRefreshTokenFn: (scope: string, server: string, clientConfig: IPublicClientConfig, tokens: IOdspTokens) => () => Promise<string>;

// @internal (undocumented)
export function getServer(tenantId: string): string;
Expand All @@ -82,14 +82,6 @@ export function getSPOAndGraphRequestIdsFromResponse(headers: {
// @internal (undocumented)
export function hasFacetCodes(x: any): x is Pick<IOdspErrorAugmentations, "facetCodes">;

// @internal (undocumented)
export interface IClientConfig {
// (undocumented)
clientId: string;
// (undocumented)
clientSecret: string;
}

// @alpha (undocumented)
export interface IOdspAuthRequestInfo {
// (undocumented)
Expand Down Expand Up @@ -120,6 +112,12 @@ export interface IOdspTokens {
readonly refreshToken: string;
}

// @internal
export interface IPublicClientConfig {
// (undocumented)
clientId: string;
}

// @internal (undocumented)
export function isOdspHostname(server: string): boolean;

Expand Down Expand Up @@ -169,7 +167,7 @@ export const pushScope = "offline_access https://pushchannel.1drv.ms/PushChannel
export function putAsync(url: string, authRequestInfo: IOdspAuthRequestInfo): Promise<Response>;

// @internal
export function refreshTokens(server: string, scope: string, clientConfig: IClientConfig, tokens: IOdspTokens): Promise<IOdspTokens>;
export function refreshTokens(server: string, scope: string, clientConfig: IPublicClientConfig, tokens: IOdspTokens): Promise<IOdspTokens>;

// @internal
export function throwOdspNetworkError(errorMessage: string, statusCode: number, response: Response, responseText?: string, props?: ITelemetryBaseProperties): never;
Expand Down
7 changes: 6 additions & 1 deletion packages/utils/odsp-doclib-utils/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,11 @@
"typescript": "~5.1.6"
},
"typeValidation": {
"broken": {}
"broken": {
"RemovedInterfaceDeclaration_IClientConfig": {
"backCompat": false,
"forwardCompat": false
}
}
}
}
2 changes: 1 addition & 1 deletion packages/utils/odsp-doclib-utils/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export {
getOdspScope,
getPushRefreshTokenFn,
getRefreshTokenFn,
IClientConfig,
IPublicClientConfig,
IOdspAuthRequestInfo,
IOdspTokens,
pushScope,
Expand Down
18 changes: 8 additions & 10 deletions packages/utils/odsp-doclib-utils/src/odspAuth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,11 @@ export interface IOdspTokens {
}

/**
* Configuration for a public client.
* @internal
*/
export interface IClientConfig {
export interface IPublicClientConfig {
clientId: string;
clientSecret: string;
}

/**
Expand Down Expand Up @@ -55,7 +55,6 @@ export type TokenRequestCredentials =

type TokenRequestBody = TokenRequestCredentials & {
client_id: string;
client_secret: string;
scope: string;
};

Expand All @@ -81,7 +80,7 @@ export function getFetchTokenUrl(server: string): string {
*/
export function getLoginPageUrl(
server: string,
clientConfig: IClientConfig,
clientConfig: IPublicClientConfig,
scope: string,
odspAuthRedirectUri: string,
) {
Expand All @@ -99,22 +98,22 @@ export function getLoginPageUrl(
*/
export const getOdspRefreshTokenFn = (
server: string,
clientConfig: IClientConfig,
clientConfig: IPublicClientConfig,
tokens: IOdspTokens,
) => getRefreshTokenFn(getOdspScope(server), server, clientConfig, tokens);
/**
* @internal
*/
export const getPushRefreshTokenFn = (
server: string,
clientConfig: IClientConfig,
clientConfig: IPublicClientConfig,
tokens: IOdspTokens,
) => getRefreshTokenFn(pushScope, server, clientConfig, tokens);
/**
* @internal
*/
export const getRefreshTokenFn =
(scope: string, server: string, clientConfig: IClientConfig, tokens: IOdspTokens) =>
(scope: string, server: string, clientConfig: IPublicClientConfig, tokens: IOdspTokens) =>
async () => {
const newTokens = await refreshTokens(server, scope, clientConfig, tokens);
return newTokens.accessToken;
Expand All @@ -131,13 +130,12 @@ export const getRefreshTokenFn =
export async function fetchTokens(
server: string,
scope: string,
clientConfig: IClientConfig,
clientConfig: IPublicClientConfig,
credentials: TokenRequestCredentials,
): Promise<IOdspTokens> {
const body: TokenRequestBody = {
scope,
client_id: clientConfig.clientId,
client_secret: clientConfig.clientSecret,
...credentials,
};
const response = await unauthPostAsync(
Expand Down Expand Up @@ -206,7 +204,7 @@ function isAccessTokenError(parsedResponse: any): parsedResponse is AadOauth2Tok
export async function refreshTokens(
server: string,
scope: string,
clientConfig: IClientConfig,
clientConfig: IPublicClientConfig,
tokens: IOdspTokens,
): Promise<IOdspTokens> {
// Clear out the old tokens while awaiting the new tokens
Expand Down
Loading
Loading