forked from microsoft/BotFramework-Composer
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
enable option to require authentication for abs-h (microsoft#817)
* add auth utils with method to get user token * move loading project into main router * update launch config for server * enable absh as auth provider on server * use COMPOSER_* for client env vars * update client-side auth * move action types to actions dir start to make use of discriminated union types to strongly type the store dispatch * move project templates into store allows us to handle error conditions better * handle session expired * move token management to store allows us to use store mechanics to handle when the user's session state changes * use store to login user in component * handle blocked popups use a redirect strategy if a browser blocks popups * only cancel api requests after getting 401 * show message and prompt user to login when session expires * use different env vars to construct login url * add authentication doc * decode user token and put results into state * refresh user token 5 minutes before it expires * add test for jwt expiration * update session expired message * get auth resource from env var * fix bad merge * correct usage of fetchTemplates * fix nav bar spec when landing on home page, the bot won't automatically load * use lodash.once * only set up axios when auth is required
- Loading branch information
1 parent
6e6fab3
commit e0ec01f
Showing
34 changed files
with
1,015 additions
and
100 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
{ | ||
// See https://go.microsoft.com/fwlink/?LinkId=733558 | ||
// for the documentation about the tasks.json format | ||
"version": "2.0.0", | ||
"tasks": [ | ||
{ | ||
"label": "server: build", | ||
"type": "npm", | ||
"script": "build", | ||
"path": "Composer/packages/server/", | ||
"problemMatcher": [] | ||
} | ||
] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
import { isTokenExpired } from '../../src/utils/auth'; | ||
|
||
// token that expires on Sep 5, 2019 @ 14:00 PDT | ||
const jwtToken = | ||
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1Njc3MTcyMDB9.YZbb01qF36O-GbKNOqxsuZe1fOg3kUtcimRUGHp42VI'; | ||
|
||
describe('isTokenExpired', () => { | ||
it('is false when token is valid', () => { | ||
// @ts-ignore | ||
Date.now = jest.spyOn(Date, 'now').mockImplementation(() => 1567630800000); // 2019-09-04 14:00 PDT | ||
expect(isTokenExpired(jwtToken)).toBe(false); | ||
}); | ||
|
||
it('is true when token cannot be decoded', () => { | ||
expect(isTokenExpired('invalid token')).toBe(true); | ||
}); | ||
|
||
it('is true when token is expired', () => { | ||
// @ts-ignore | ||
Date.now = jest.spyOn(Date, 'now').mockImplementation(() => 1567717200000); // 2019-09-05 14:00 PDT | ||
expect(isTokenExpired(jwtToken)).toBe(true); | ||
|
||
// @ts-ignore | ||
Date.now = jest.spyOn(Date, 'now').mockImplementation(() => 1567803600000); // 2019-09-06 14:00 PDT | ||
expect(isTokenExpired(jwtToken)).toBe(true); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
67 changes: 67 additions & 0 deletions
67
Composer/packages/client/src/components/RequireAuth/index.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
import React, { useEffect, useState, useContext } from 'react'; | ||
import { Spinner, SpinnerSize, Dialog, DialogType, DialogFooter, PrimaryButton } from 'office-ui-fabric-react'; | ||
import formatMessage from 'format-message'; | ||
import once from 'lodash.once'; | ||
|
||
import { StoreContext } from '../../store'; | ||
|
||
import { loading, dialog, consoleStyle } from './styles'; | ||
|
||
// only attempt to login once | ||
const loginOnce = once((login: () => void) => { | ||
if (process.env.COMPOSER_REQUIRE_AUTH) { | ||
login(); | ||
} | ||
}); | ||
|
||
export const RequireAuth: React.FC = props => { | ||
const [isLoading, setIsLoading] = useState<boolean>(true); | ||
const { state, actions } = useContext(StoreContext); | ||
const { currentUser } = state; | ||
|
||
useEffect(() => { | ||
loginOnce(actions.loginUser); | ||
}, []); | ||
|
||
useEffect(() => { | ||
setIsLoading(!currentUser.token); | ||
}, [currentUser.token]); | ||
|
||
const sessionExpiredDialog = currentUser.sessionExpired && ( | ||
<Dialog | ||
hidden={false} | ||
onDismiss={() => false} | ||
dialogContentProps={{ | ||
type: DialogType.normal, | ||
title: formatMessage('Session expired'), | ||
styles: dialog, | ||
}} | ||
modalProps={{ | ||
isBlocking: false, | ||
styles: { main: { maxWidth: 450 } }, | ||
}} | ||
> | ||
<div css={consoleStyle}>{formatMessage('Please log in before continuing.')}</div> | ||
<DialogFooter> | ||
<PrimaryButton onClick={() => actions.loginUser()} text={formatMessage('Login')} /> | ||
</DialogFooter> | ||
</Dialog> | ||
); | ||
|
||
if (process.env.COMPOSER_REQUIRE_AUTH) { | ||
if (!currentUser.sessionExpired && isLoading) { | ||
return ( | ||
<div css={loading}> | ||
<Spinner label={formatMessage('Loading...')} size={SpinnerSize.large} /> | ||
</div> | ||
); | ||
} | ||
} | ||
|
||
return ( | ||
<> | ||
{sessionExpiredDialog} | ||
{props.children} | ||
</> | ||
); | ||
}; |
Oops, something went wrong.