diff --git a/packages/teleport/src/Databases/ConnectDialog/ConnectDialog.story.tsx b/packages/teleport/src/Databases/ConnectDialog/ConnectDialog.story.tsx index 8c92ee51e..160be5907 100644 --- a/packages/teleport/src/Databases/ConnectDialog/ConnectDialog.story.tsx +++ b/packages/teleport/src/Databases/ConnectDialog/ConnectDialog.story.tsx @@ -31,3 +31,17 @@ export const Connect = () => ( authType="local" /> ); + +export const ConnectWithRequestId = () => { + return ( + null} + authType="local" + accessRequestId="e1e8072c-1eb8-5df4-a7bd-b6863b19271c" + /> + ); +}; diff --git a/packages/teleport/src/Databases/ConnectDialog/ConnectDialog.tsx b/packages/teleport/src/Databases/ConnectDialog/ConnectDialog.tsx index 7e0cca71a..da25a5041 100644 --- a/packages/teleport/src/Databases/ConnectDialog/ConnectDialog.tsx +++ b/packages/teleport/src/Databases/ConnectDialog/ConnectDialog.tsx @@ -31,6 +31,7 @@ export default function ConnectDialog({ dbName, onClose, authType, + accessRequestId, }: Props) { const { hostname, port } = window.document.location; const host = `${hostname}:${port || '443'}`; @@ -40,6 +41,10 @@ export default function ConnectDialog({ ? `tsh login --proxy=${host}` : `tsh login --proxy=${host} --auth=local --user=${username}`; + const requestIdFlag = accessRequestId + ? ` --request-id=${accessRequestId}` + : ''; + return ( ({ @@ -59,14 +64,17 @@ export default function ConnectDialog({ Step 1 {' - Login to Teleport'} - + Step 2 {' - Retrieve credentials for the database'} - ] [--db-name=] ${dbName}`} /> + ] [--db-name=] ${dbName}`} + /> @@ -105,4 +113,5 @@ export type Props = { username: string; clusterId: string; authType: AuthType; + accessRequestId?: string; }; diff --git a/packages/teleport/src/Databases/DatabaseList/DatabaseList.tsx b/packages/teleport/src/Databases/DatabaseList/DatabaseList.tsx index c297bbb55..b5da4039a 100644 --- a/packages/teleport/src/Databases/DatabaseList/DatabaseList.tsx +++ b/packages/teleport/src/Databases/DatabaseList/DatabaseList.tsx @@ -45,6 +45,7 @@ function DatabaseList(props: Props) { pathname, replaceHistory, onLabelClick, + accessRequestId, } = props; const [dbConnectInfo, setDbConnectInfo] = useState<{ @@ -117,6 +118,7 @@ function DatabaseList(props: Props) { dbProtocol={dbConnectInfo.protocol} onClose={() => setDbConnectInfo(null)} authType={authType} + accessRequestId={accessRequestId} /> )} @@ -165,6 +167,7 @@ type Props = { pathname: string; replaceHistory: (path: string) => void; onLabelClick: (label: AgentLabel) => void; + accessRequestId?: string; }; export default DatabaseList; diff --git a/packages/teleport/src/Databases/Databases.story.tsx b/packages/teleport/src/Databases/Databases.story.tsx index a4a8de959..ec1987567 100644 --- a/packages/teleport/src/Databases/Databases.story.tsx +++ b/packages/teleport/src/Databases/Databases.story.tsx @@ -84,4 +84,5 @@ export const props: State = { replaceHistory: () => null, isSearchEmpty: false, onLabelClick: () => null, + accessRequestId: null, }; diff --git a/packages/teleport/src/Databases/Databases.tsx b/packages/teleport/src/Databases/Databases.tsx index 61e4de094..66ad5ab34 100644 --- a/packages/teleport/src/Databases/Databases.tsx +++ b/packages/teleport/src/Databases/Databases.tsx @@ -63,6 +63,7 @@ export function Databases(props: State) { fetchStatus, isSearchEmpty, onLabelClick, + accessRequestId, } = props; const hasNoDatabases = @@ -111,6 +112,7 @@ export function Databases(props: State) { pathname={pathname} replaceHistory={replaceHistory} onLabelClick={onLabelClick} + accessRequestId={accessRequestId} /> )} diff --git a/packages/teleport/src/Databases/useDatabases.ts b/packages/teleport/src/Databases/useDatabases.ts index 40a49209e..55a51639c 100644 --- a/packages/teleport/src/Databases/useDatabases.ts +++ b/packages/teleport/src/Databases/useDatabases.ts @@ -38,6 +38,7 @@ export default function useDatabases(ctx: Ctx) { const isEnterprise = ctx.isEnterprise; const version = ctx.storeUser.state.cluster.authVersion; const authType = ctx.storeUser.state.authType; + const accessRequestId = ctx.storeUser.getAccessRequestId(); const [isAddDialogVisible, setIsAddDialogVisible] = useState(false); const [fetchStatus, setFetchStatus] = useState(''); const [params, setParams] = useState({ @@ -173,6 +174,7 @@ export default function useDatabases(ctx: Ctx) { fetchStatus, isSearchEmpty, onLabelClick, + accessRequestId, }; } diff --git a/packages/teleport/src/Kubes/ConnectDialog/ConnectDialog.story.tsx b/packages/teleport/src/Kubes/ConnectDialog/ConnectDialog.story.tsx index 4a11bfd2d..92e87fc79 100644 --- a/packages/teleport/src/Kubes/ConnectDialog/ConnectDialog.story.tsx +++ b/packages/teleport/src/Kubes/ConnectDialog/ConnectDialog.story.tsx @@ -33,6 +33,19 @@ export const Local = () => { ); }; +export const LocalWithRequestId = () => { + return ( + null} + username={'sam'} + authType={'local'} + kubeConnectName={'tele.logicoma.dev-prod'} + clusterId={'some-cluster-name'} + accessRequestId={'8289cdb1-385c-5b02-85f1-fa2a934b749f'} + /> + ); +}; + export const Sso = () => { return ( {' - Login to Teleport'} - + @@ -90,6 +104,7 @@ type Props = { authType: AuthType; kubeConnectName: string; clusterId: string; + accessRequestId?: string; }; const dialogCss = () => ` diff --git a/packages/teleport/src/Kubes/KubeList/KubeList.tsx b/packages/teleport/src/Kubes/KubeList/KubeList.tsx index 35282228d..54378a0e0 100644 --- a/packages/teleport/src/Kubes/KubeList/KubeList.tsx +++ b/packages/teleport/src/Kubes/KubeList/KubeList.tsx @@ -45,6 +45,7 @@ function KubeList(props: Props) { pathname, replaceHistory, onLabelClick, + accessRequestId, } = props; const [kubeConnectName, setKubeConnectName] = useState(''); @@ -103,6 +104,7 @@ function KubeList(props: Props) { authType={authType} kubeConnectName={kubeConnectName} clusterId={clusterId} + accessRequestId={accessRequestId} /> )} @@ -141,6 +143,7 @@ type Props = { pathname: string; replaceHistory: (path: string) => void; onLabelClick: (label: AgentLabel) => void; + accessRequestId?: string; }; export default KubeList; diff --git a/packages/teleport/src/Kubes/Kubes.story.tsx b/packages/teleport/src/Kubes/Kubes.story.tsx index 3ab22bc78..b31d39fd2 100644 --- a/packages/teleport/src/Kubes/Kubes.story.tsx +++ b/packages/teleport/src/Kubes/Kubes.story.tsx @@ -80,4 +80,5 @@ export const props: State = { replaceHistory: () => null, isSearchEmpty: false, onLabelClick: () => null, + accessRequestId: null, }; diff --git a/packages/teleport/src/Kubes/Kubes.tsx b/packages/teleport/src/Kubes/Kubes.tsx index e88c6d9ed..ee0e78ef0 100644 --- a/packages/teleport/src/Kubes/Kubes.tsx +++ b/packages/teleport/src/Kubes/Kubes.tsx @@ -60,6 +60,7 @@ export function Kubes(props: State) { fetchStatus, isSearchEmpty, onLabelClick, + accessRequestId, } = props; const [showAddKube, setShowAddKube] = useState(false); @@ -110,6 +111,7 @@ export function Kubes(props: State) { pathname={pathname} replaceHistory={replaceHistory} onLabelClick={onLabelClick} + accessRequestId={accessRequestId} /> )} diff --git a/packages/teleport/src/Kubes/useKubes.ts b/packages/teleport/src/Kubes/useKubes.ts index ba6a9f2c4..7be06cc5c 100644 --- a/packages/teleport/src/Kubes/useKubes.ts +++ b/packages/teleport/src/Kubes/useKubes.ts @@ -34,6 +34,7 @@ export default function useKubes(ctx: TeleportContext) { const { search, pathname } = useLocation(); const [startKeys, setStartKeys] = useState([]); const canCreate = ctx.storeUser.getTokenAccess().create; + const accessRequestId = ctx.storeUser.getAccessRequestId(); const { attempt, setAttempt } = useAttempt('processing'); const [fetchStatus, setFetchStatus] = useState(''); const [params, setParams] = useState({ @@ -155,6 +156,7 @@ export default function useKubes(ctx: TeleportContext) { fetchStatus, isSearchEmpty, onLabelClick, + accessRequestId, }; } diff --git a/packages/teleport/src/services/user/makeUserContext.ts b/packages/teleport/src/services/user/makeUserContext.ts index 3ca0d9634..da33d1a72 100644 --- a/packages/teleport/src/services/user/makeUserContext.ts +++ b/packages/teleport/src/services/user/makeUserContext.ts @@ -22,6 +22,7 @@ export default function makeUserContext(json: any): UserContext { json = json || {}; const username = json.userName; const authType = json.authType; + const accessRequestId = json.accessRequestId; const cluster = makeCluster(json.cluster); const acl = makeAcl(json.userAcl); @@ -35,6 +36,7 @@ export default function makeUserContext(json: any): UserContext { cluster, accessStrategy, accessCapabilities, + accessRequestId, }; } diff --git a/packages/teleport/src/services/user/types.ts b/packages/teleport/src/services/user/types.ts index cf06c663d..3e509c168 100644 --- a/packages/teleport/src/services/user/types.ts +++ b/packages/teleport/src/services/user/types.ts @@ -35,6 +35,8 @@ export interface UserContext { cluster: Cluster; accessStrategy: AccessStrategy; accessCapabilities: AccessCapabilities; + // accessRequestId is the ID of the access request from which additional roles to assume were obtained for the current session. + accessRequestId?: string; } export interface Access { diff --git a/packages/teleport/src/stores/storeUserContext.ts b/packages/teleport/src/stores/storeUserContext.ts index b2dbdbc7e..c5378dc7d 100644 --- a/packages/teleport/src/stores/storeUserContext.ts +++ b/packages/teleport/src/stores/storeUserContext.ts @@ -100,4 +100,8 @@ export default class StoreUserContext extends Store { getNodeAccess() { return this.state.acl.nodes; } + + getAccessRequestId() { + return this.state.accessRequestId; + } }