Skip to content

Commit

Permalink
Merge branch 'refs/heads/develop' into gr-DCJ-163-auth-design-overview
Browse files Browse the repository at this point in the history
  • Loading branch information
rushtong committed Sep 19, 2024
2 parents 3b7f0dc + 1652274 commit 4ffce4c
Show file tree
Hide file tree
Showing 36 changed files with 892 additions and 634 deletions.
12 changes: 12 additions & 0 deletions .github/workflows/component-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,15 @@ jobs:
install: false
component: true
browser: chrome
- uses: actions/upload-artifact@v4
if: failure()
with:
name: cypress-screenshots
path: cypress/screenshots
if-no-files-found: ignore # 'warn' or 'error' are also available, defaults to `warn`
- uses: actions/upload-artifact@v4
if: failure()
with:
name: cypress-videos
path: cypress/videos
if-no-files-found: ignore # 'warn' or 'error' are also available, defaults to `warn`
17 changes: 10 additions & 7 deletions DEVNOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,12 @@ nvm install 22.6.0
npm install
```

3. Install configs for an environment. This example is for the `alpha` environment, but you can use values from any environment by looking at the deployed configs in https://duos-k8s.dsde-{%ENV%}.broadinstitute.org/config.json where {%ENV%} is any of `dev`, `staging`, `alpha`, or `prod`
Remember to set the `env` value appropriately. We use `local` for running via npm, but under docker, we use a real env like `dev`.
The installation steps outlined in this step can also be completed using the [render-configs.sh](scripts/render-configs.sh) script which can generate all required
files for local development.
3. Install configs for an environment. This example is for the `alpha` environment, but you can use values from any
environment by looking at the deployed configs in https://duos-k8s.dsde-{%ENV%}.broadinstitute.org/config.json where
{%ENV%} is any of `dev`, `staging`, `alpha`, or `prod`. Remember to set the `env` value appropriately, for example,
`dev`. Certain features are available only in specific environments. Setting the `env` value to the desired environment
will simulate it for local development. The installation steps outlined in this step can also be completed using the
[render-configs.sh](scripts/render-configs.sh) script which can generate all required files for local development.
```
cp config/alpha.json public/config.json
```
Expand Down Expand Up @@ -50,8 +52,9 @@ npm start
```
### Running under Docker

Update your local `docker-compose.yaml` file to mount the preferred `config.json` file in app volumes.
Remember to set the `env` value appropriately in `config.json`. We use `local` for running via npm, but under docker, we use a real env like `dev`
Update your local `docker-compose.yaml` file to mount the preferred `config.json` file in app volumes. Remember to set
the `env` value appropriately, for example, `dev`. Certain features are available only in specific environments. Setting
the `env` value to the desired environment will simulate it for local development.

```yaml
volumes:
Expand All @@ -78,7 +81,7 @@ run in GitHub Actions. Create a `cypress.env.json` file in the root of your
local repo that looks like this:
```json
{
"baseUrl": "https://local.dsde-dev,broadinstitute.org:3000/"
"baseUrl": "https://local.dsde-dev.broadinstitute.org:3000/"
}
```
Cypress will use these values in `cypress.config.js` and `cypress/support/commands.js`
Expand Down
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# builder image
FROM node:22.7.0 AS builder
FROM node:22.8.0 AS builder
LABEL maintainer="grushton@broadinstitute.org"

# set working directory
Expand Down
1 change: 0 additions & 1 deletion config/alpha.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
"hash": "alpha",
"apiUrl": "https://consent.dsde-alpha.broadinstitute.org",
"ontologyApiUrl": "https://consent-ontology.dsde-alpha.broadinstitute.org/",
"clientId": "1020846292598-hd801vsmmbhh97vaf6aar17lu0q2evfj.apps.googleusercontent.com",
"errorApiKey": "1234567890abcdefghijklmnop",
"gaId": "",
"profileUrl": "https://profile-dot-broad-shibboleth-prod.appspot.com/dev",
Expand Down
1 change: 0 additions & 1 deletion config/base_config.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
"ontologyApiUrl": "",
"terraUrl": "",
"tdrApiUrl": "",
"clientId": "",
"errorApiKey": "",
"nihUrl": "",
"gaId": "",
Expand Down
61 changes: 61 additions & 0 deletions cypress/component/Auth/auth.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/* eslint-disable no-undef */

import {OidcBroker} from '../../../src/libs/auth/oidcBroker';
import {Auth} from '../../../src/libs/auth/auth';
import {OAuth2} from '../../../src/libs/ajax/OAuth2';
import {Storage} from '../../../src/libs/storage';
import {v4 as uuid} from 'uuid';
import {mockOidcUser} from './mockOidcUser';

describe('Auth Failure', function () {
it('Sign In error throws expected message', async function () {
cy.stub(OidcBroker, 'signIn').returns(null);
cy.on('fail', (err) => {
return err.message !== Auth.signInError();
});
Auth.signIn().then(() => {
expect(Storage.getOidcUser()).to.be.null;
expect(Storage.userIsLogged()).to.be.false;
});
});
});

describe('Auth Success', function () {
// Intercept configuration calls
beforeEach(() => {
cy.intercept({
method: 'GET',
url: '/config.json',
hostname: 'localhost',
}, {'env': 'ci'});
cy.stub(OAuth2, 'getConfig').returns({
'authorityEndpoint': Cypress.config().baseUrl,
'clientId': 'clientId'
});
Auth.initialize();
});

it('Sign In stores the current user', async function () {
cy.stub(OidcBroker, 'signIn').returns(mockOidcUser);
await Auth.signIn();
expect(Storage.getOidcUser()).to.not.be.empty;
expect(Storage.userIsLogged()).to.be.true;
});

it('Sign Out Clears the session when called', async function () {
Storage.setUserIsLogged(true);
Storage.setAnonymousId(uuid());
Storage.setData('key', 'val');
Storage.setEnv('test');
expect(Storage.userIsLogged()).to.be.true;
expect(Storage.getAnonymousId()).to.not.be.empty;
expect(Storage.getData('key')).to.not.be.empty;
expect(Storage.getEnv()).to.not.be.empty;
await Auth.signOut();
expect(Storage.userIsLogged()).to.be.false;
expect(Storage.getAnonymousId()).to.be.null;
expect(Storage.getData('key')).to.be.null;
expect(Storage.getEnv()).to.be.null;
});

});
29 changes: 29 additions & 0 deletions cypress/component/Auth/mockOidcUser.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import {OidcUser} from "../../../src/libs/auth/oidcBroker";

export const mockOidcUser: OidcUser = {
access_token: '',
get expires_in(): number | undefined {
return undefined;
},
session_state: undefined,
state: undefined,
token_type: '',
get expired(): boolean | undefined {
return undefined;
},
get scopes(): string[] {
return [];
},
toStorageString(): string {
return '';
},
profile: {
jti: undefined,
nbf: undefined,
sub: undefined,
iss: '',
aud: '',
exp: 0,
iat: 0
}
};
66 changes: 66 additions & 0 deletions cypress/component/Auth/oidcBroker.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/* eslint-disable no-undef */

import {OAuth2} from '../../../src/libs/ajax/OAuth2';
import {OidcBroker} from '../../../src/libs/auth/oidcBroker';

describe('OidcBroker Failure', function () {

it('Get User Manager Fails without initialization', function () {
cy.on('fail', (err) => {
return !err.message.includes('initialized');
});
OidcBroker.getUserManager();
});

it('Get User Manager Settings Fails without initialization', function () {
cy.on('fail', (err) => {
return !err.message.includes('initialized');
});
OidcBroker.getUserManagerSettings();
});

});

describe('OidcBroker Success', function () {
// Intercept configuration calls
beforeEach(() => {
cy.intercept({
method: 'GET',
url: '/config.json',
hostname: 'localhost',
}, {'env': 'ci'});
cy.stub(OAuth2, 'getConfig').returns({
'authorityEndpoint': Cypress.config().baseUrl,
'clientId': 'clientId'
});
});

it('Initialization Succeeds', async function () {
await OidcBroker.initialize();
expect(OidcBroker.getUserManager()).to.not.be.null;
expect(OidcBroker.getUserManagerSettings()).to.not.be.null;
});

it('Sign In calls Oidc Broker UserManager sign-in popup function', async function () {
await OidcBroker.initialize();
const um = OidcBroker.getUserManager();
cy.spy(um, 'signinPopup').as('signinPopup');
// Since we are not calling a real sign-in url, we expect oidc-client errors when doing so
cy.on('uncaught:exception', (err) => {
return !(err.message.includes('Invalid URL'))
});
OidcBroker.signIn();
expect(um.signinPopup).to.be.called;
});

it('Sign Out calls Oidc UserManager sign-out functions', async function () {
await OidcBroker.initialize();
const um = OidcBroker.getUserManager();
cy.spy(um, 'removeUser').as('removeUser');
cy.spy(um, 'clearStaleState').as('clearStaleState');
await OidcBroker.signOut();
expect(um.removeUser).to.be.called;
expect(um.clearStaleState).to.be.called;
});

});
Original file line number Diff line number Diff line change
Expand Up @@ -464,9 +464,7 @@ const dar = {
'createUserId': null,
'updateDate': 1643730658770,
'updateUserId': 11111,
'active': true,
'consentName': null,
'needsApproval': null,
'alias': 999,
'datasetIdentifier': 'DUOS-00999',
'dataUse': {
Expand Down Expand Up @@ -670,8 +668,6 @@ const dacDatasets = [{
'propertyValue': 'Sleep Apnea'
}
],
'active': true,
'needsApproval': true,
'isAssociatedToDataOwners': null,
'updateAssociationToDataOwnerAllowed': null,
'alias': 999,
Expand Down
48 changes: 0 additions & 48 deletions cypress/component/SignIn/google_is.spec.js

This file was deleted.

Loading

0 comments on commit 4ffce4c

Please sign in to comment.