diff --git a/packages/teleport/src/AppLauncher/AppLauncher.story.tsx b/packages/teleport/src/AppLauncher/AppLauncher.story.tsx
index c4699e0c5..c248c1fcb 100644
--- a/packages/teleport/src/AppLauncher/AppLauncher.story.tsx
+++ b/packages/teleport/src/AppLauncher/AppLauncher.story.tsx
@@ -16,16 +16,16 @@
import React from 'react';
-import { AppLauncher } from './AppLauncher';
+import { AppLauncherAccessDenied, AppLauncherProcessing } from './AppLauncher';
export default {
title: 'Teleport/AppLauncher',
};
export const Processing = () => {
- return ;
+ return ;
};
export const Failed = () => {
- return ;
+ return ;
};
diff --git a/packages/teleport/src/AppLauncher/AppLauncher.tsx b/packages/teleport/src/AppLauncher/AppLauncher.tsx
index 75aeb6259..a3ab01054 100644
--- a/packages/teleport/src/AppLauncher/AppLauncher.tsx
+++ b/packages/teleport/src/AppLauncher/AppLauncher.tsx
@@ -14,25 +14,93 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
-import React from 'react';
+import React, { useCallback, useEffect } from 'react';
+
+import { useLocation, useParams } from 'react-router';
+
import { Flex, Indicator } from 'design';
+
import { AccessDenied } from 'design/CardError';
-import useAppLauncher from './useAppLauncher';
+import useAttempt from 'shared/hooks/useAttemptNext';
-export default function Container() {
- const state = useAppLauncher();
- return ;
-}
+import { UrlLauncherParams } from 'teleport/config';
+import service from 'teleport/services/apps';
+
+export function AppLauncher() {
+ const { attempt, setAttempt } = useAttempt('processing');
+
+ const params = useParams();
+ const { search } = useLocation();
+ const queryParams = new URLSearchParams(search);
+
+ const createAppSession = useCallback(async (params: UrlLauncherParams) => {
+ try {
+ let fqdn = params.fqdn;
+ if (!fqdn) {
+ const app = await service.getAppFqdn(params);
+
+ fqdn = app.fqdn;
+ }
+
+ const port = location.port ? `:${location.port}` : '';
+ const session = await service.createAppSession(params);
+
+ await fetch(`https://${fqdn}${port}/x-teleport-auth`, {
+ method: 'POST',
+ credentials: 'include',
+ headers: {
+ 'X-Cookie-Value': session.cookieValue,
+ 'X-Subject-Cookie-Value': session.subjectCookieValue,
+ },
+ });
+
+ let path = '';
+ if (queryParams.has('path')) {
+ path = decodeURIComponent(queryParams.get('path'));
-export function AppLauncher(props: ReturnType) {
- if (props.status === 'failed') {
- return ;
+ if (!path.startsWith('/')) {
+ path = `/${path}`;
+ }
+ }
+
+ window.location.replace(`https://${fqdn}${port}${path}`);
+ } catch (err) {
+ let statusText = 'Something went wrong';
+ if (err instanceof Error) {
+ statusText = err.message;
+ }
+
+ setAttempt({
+ status: 'failed',
+ statusText,
+ });
+ }
+ }, []);
+
+ useEffect(() => {
+ createAppSession(params);
+ }, [params]);
+
+ if (attempt.status === 'failed') {
+ return ;
}
+ return ;
+}
+
+export function AppLauncherProcessing() {
return (
);
}
+
+interface AppLauncherAccessDeniedProps {
+ statusText: string;
+}
+
+export function AppLauncherAccessDenied(props: AppLauncherAccessDeniedProps) {
+ return ;
+}
diff --git a/packages/teleport/src/AppLauncher/index.ts b/packages/teleport/src/AppLauncher/index.ts
index c2164ef30..c0ac6c47d 100644
--- a/packages/teleport/src/AppLauncher/index.ts
+++ b/packages/teleport/src/AppLauncher/index.ts
@@ -14,5 +14,4 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
-import AppLauncher from './AppLauncher';
-export default AppLauncher;
+export { AppLauncher as default } from './AppLauncher';
diff --git a/packages/teleport/src/AppLauncher/useAppLauncher.ts b/packages/teleport/src/AppLauncher/useAppLauncher.ts
deleted file mode 100644
index bea986bb3..000000000
--- a/packages/teleport/src/AppLauncher/useAppLauncher.ts
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
-Copyright 2020 Gravitational, Inc.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-import React from 'react';
-import { useParams } from 'react-router';
-
-import useAttempt from 'shared/hooks/useAttemptNext';
-
-import service from 'teleport/services/apps';
-import { UrlLauncherParams } from 'teleport/config';
-import { getUrlParameter } from 'teleport/services/history';
-
-export default function useAppLauncher() {
- const params = useParams();
- const { attempt, setAttempt } = useAttempt('processing');
-
- React.useEffect(() => {
- resolveRedirectUrl(params)
- .then(url => {
- window.location.replace(url);
- })
- .catch((err: Error) => {
- setAttempt({
- status: 'failed',
- statusText: err.message,
- });
- });
- }, []);
-
- return {
- ...attempt,
- };
-}
-
-function resolveRedirectUrl(params: UrlLauncherParams) {
- const location = window.location;
- const port = location.port ? ':' + location.port : '';
- const state = getUrlParameter('state', location.search);
- const arn = getUrlParameter('awsrole', location.search);
- // redirectPath captures and pass any requested App Access path during the `x-teleport-auth` process
- const redirectPath = getUrlParameter('path', location.search);
-
- // no state value: let the target app know of a new auth exchange
- if (!state) {
- return service.getAppFqdn(params).then(result => {
- const url = new URL(`https://${result.fqdn}${port}/x-teleport-auth`);
- if (params.clusterId) {
- url.searchParams.set('cluster', params.clusterId);
- }
- if (params.publicAddr) {
- url.searchParams.set('addr', params.publicAddr);
- }
- if (params.arn) {
- url.searchParams.set('awsrole', decodeURIComponent(params.arn));
- }
- if (redirectPath) {
- url.searchParams.set('path', redirectPath);
- }
- return url.toString();
- });
- }
-
- // state value received: create new session for the target app
- if (arn) {
- params.arn = arn;
- }
- return service.createAppSession(params).then(result => {
- const url = new URL(`https://${result.fqdn}${port}/x-teleport-auth`);
- url.searchParams.set('state', state);
- url.searchParams.append('subject', result.subject);
- url.hash = `#value=${result.value}`;
- if (redirectPath) {
- url.searchParams.set('path', redirectPath);
- }
- return url.toString();
- });
-}
diff --git a/packages/teleport/src/services/apps/apps.ts b/packages/teleport/src/services/apps/apps.ts
index 6b6de97a3..a9ecec2f6 100644
--- a/packages/teleport/src/services/apps/apps.ts
+++ b/packages/teleport/src/services/apps/apps.ts
@@ -50,6 +50,8 @@ const service = {
fqdn: json.fqdn as string,
value: json.value as string,
subject: json.subject as string,
+ cookieValue: json.cookie_value as string,
+ subjectCookieValue: json.subject_cookie_value as string,
}));
},