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

Cognito hosted ui #585

Merged
merged 33 commits into from
Apr 13, 2018
Merged
Show file tree
Hide file tree
Changes from 27 commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
17f0285
mionr chnage
powerful23 Mar 22, 2018
0205024
Merge remote-tracking branch 'upstream/master' into cognito-hosted-ui
powerful23 Mar 22, 2018
e2c0202
mionr change
powerful23 Mar 23, 2018
b7ee2fe
mionr change
powerful23 Mar 23, 2018
118560c
merge upstream
powerful23 Mar 28, 2018
ebcbb77
mionr change
powerful23 Mar 29, 2018
d7b33bb
mionr change
powerful23 Mar 30, 2018
957d7ea
documentation updated
powerful23 Apr 3, 2018
711bc54
mionr change
powerful23 Apr 3, 2018
9ad6619
Merge remote-tracking branch 'upstream/master' into cognito-hosted-ui
powerful23 Apr 3, 2018
373ddf5
merge from upstream
powerful23 Apr 3, 2018
cf02930
rename withCognito to withHostedCognito
powerful23 Apr 3, 2018
b4bb820
unit tests fix
powerful23 Apr 3, 2018
68d1846
authenticator and auth_configure fix
powerful23 Apr 5, 2018
ac63813
Merge remote-tracking branch 'upstream/master' into cognito-hosted-ui
powerful23 Apr 5, 2018
cde081b
cognito session refresh and unit tests
powerful23 Apr 5, 2018
facffd6
version claim
powerful23 Apr 6, 2018
b2c14d2
unit tests for aws-amplify-react
powerful23 Apr 6, 2018
053a9e5
Merge branch 'master' into cognito-hosted-ui
powerful23 Apr 6, 2018
0908d71
Merge remote-tracking branch 'upstream/master' into cognito-hosted-ui
powerful23 Apr 6, 2018
523f355
documentation updated
powerful23 Apr 6, 2018
5b21c27
Merge branch 'master' into cognito-hosted-ui
mlabieniec Apr 7, 2018
bb50b90
Update authentication_guide.md
mbahar Apr 10, 2018
11f2dcc
merge from upstream
powerful23 Apr 10, 2018
4903830
update to withOAuth
powerful23 Apr 10, 2018
27d8e26
Merge remote-tracking branch 'upstream/master' into cognito-hosted-ui
powerful23 Apr 10, 2018
7078fbc
Update authentication_guide.md
mbahar Apr 11, 2018
d7b7e6e
mionr change
powerful23 Apr 12, 2018
be0225d
merge upstream
powerful23 Apr 13, 2018
1dcd5f9
mionr change
powerful23 Apr 13, 2018
73fa122
mionr change
powerful23 Apr 13, 2018
cbddcc1
docs update
powerful23 Apr 13, 2018
f3e65aa
change customAttrs to options
powerful23 Apr 13, 2018
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
118 changes: 117 additions & 1 deletion docs/media/authentication_guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -292,7 +292,7 @@ this._validAuthStates = ['signedIn'];
in the component's constructor, then implement `showComponent(theme) {}` in lieu of the typical
`render() {}` method.

### Federated Identities (Social Sign-in)
### Using Federated Identities (Social Sign-in)

**Availibility Note**
Currently, our federated identity components only support Google, Facebook and Amazon identities, and works with React.
Expand Down Expand Up @@ -352,6 +352,122 @@ const federated = {

There is also `withGoogle`, `withFacebook`, `withAmazon` components, in case you need to customize a single provider.



### Using Amazon Cognito Hosted UI

Amazon Cognito provides a customizable user experience via the hosted UI. The hosted UI supports OAuth 2.0 and Federated Identities with Facebook, Amazon, Google, and SAML providers.

Note: Amazon Cognito hosted UI feature is supported with *aws-amplify@^0.2.15* and *aws-amplify-react@^0.1.39* versions.
{: .callout .callout--info}

#### Setup your Cognito App Client

To start using hosted UI, first, you need to setup your App Client in the Amazon Cognito console.

To setup App Client;
- Go to [Amazon Cognito Console](https://aws.amazon.com/cognito/).
- Click *User Pools* on the top menu to select a User Pool or create a new one.
- Click *App integration* and *App client settings* on the left menu.
- Select *Enabled Identity Providers* and enter *Callback URL(s)* and *Sign out URL(s)* fields.
- Under the *OAuth 2.0* section, select an OAuth Flow. *Authorization code grant* is the recommended choice for security reasons.
- Choose item(s) from *OAuth Scopes*.
- Click 'Save Changes'

To enable the domain for your hosted UI;

- On the left menu, go to *App integration* > *Domain name*.
- In the *Domain prefix* section, enter the prefix for the pages that will be hosted by Amazon Cognito.

You can also enable Federated Identities for your hosted UI;

- Go to *Federation* > *Identity providers*
- Select an *Identity provider* and enter required credentials for the identity provider. (e.g., App Id, App secret, Authorized scope)
- In the settings page for your selected identity provider (Facebook, Google, etc.), set *Oauth Redirected URI* to `https://your-domain-prefix.auth.us-east 1.amazoncognito.com/oauth2/idpresponse` (*your-domain-prefix* is the domain prefix you have entered in previously).
- To retrieve user attributes from your identity provider, go to *Federation* > *Attribute mapping*. Here, you can map Federation Provider attributes to corresponding User pool attributes.

If *email* attribute is a required field in your Cognito User Pool settings, please make sure that you have selected *email* in your Authorized Scopes, and you have mapped it correctly to your User Pool attributes.
{: .callout .callout-info}

#### Configuring the Hosted UI

To configure your application for hosted UI, you need to use *hosted UI* options:

```js
import Amplify from 'aws-amplify';

const hostedUIOptions = {
// Domain name
AppWebDomain : 'your-domain-prefix.auth.us-east-1.amazoncognito.com',

// Authorized scopes
TokenScopesArray : ['phone', 'email', 'profile', 'openid','aws.cognito.signin.user.admin'],

// Callback URL
RedirectUriSignIn : 'http://www.example.com/signin',

// Sign out URL
RedirectUriSignOut : 'http://www.example.com/signout',

// Indicates if the data collection is enabled to support Cognito advanced security features. By default, this flag is set to true.
AdvancedSecurityDataCollectionFlag : true,

// 'code' for Authorization code grant,
// 'token' for Implicit grant
ResponseType: 'code'
}

Amplify.configure({
Auth: {
// other configurations...
// ....
hostedUIOptions: hostedUIOptions
},
// ...
});
```

#### Launching the Hosted UI

To invoke the browser to display the hosted UI, you need to construct the URL in your app;

```js
const config = Auth.configure();
const {
AppWebDomain,
RedirectUriSignIn,
RedirectUriSignOut,
ResponseType } = config.hostedUIOptions;

const clientId = config.userPoolWebClientId;
const url = 'https://' + AppWebDomain + '/login?redirect_uri=' + RedirectUriSignIn + '&response_type=' + ResponseType + '&client_id=' + clientId;

// Launch hosted UI
window.location.assign(url);

```

#### Launching the Hosted UI in React

With React, you can simply use `withOAuth` HOC to launch the hosted UI experience. Just wrap your app's main component with our HOC:

```js
import { withOAuth } from 'aws-amplify-react';

class MyApp extends React.Component {
// ...
render() {
return(
<button onClick={this.props.OAuthSignIn}>
Sign in with AWS
</button>
)
}
}

export default withOAuth(MyApp);
```

### Enabling MFA (Multi-Factor Authentication)

Multi-factor authentication (MFA) increases security for your app by adding an authentication method and not relying solely on username (or alias) and password. AWS Amplify uses Amazon Cognito to provide MFA. Please see [Amazon Cognito Developer Guide](https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-settings-mfa.html) for more information about setting up MFA in Amazon Cognito.
Expand Down
70 changes: 54 additions & 16 deletions packages/aws-amplify-react/__tests__/Auth/ConfirmSignIn-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ const deniedStates = [
];

describe('ConfirmSignIn', () => {
describe('normal case', () => {
describe('render test', () => {
test('render correctly with Props confirmSignIn', () => {
const wrapper = shallow(<ConfirmSignIn/>);
for (var i = 0; i < acceptedStates.length; i += 1){
Expand All @@ -33,6 +33,59 @@ describe('ConfirmSignIn', () => {
}
});

test('render corrently with other authstate', () => {
const wrapper = shallow(<ConfirmSignIn/>);

for (var i = 0; i < deniedStates.length; i += 1){
wrapper.setProps({
authState: deniedStates[i],
theme: AmplifyTheme
});

expect(wrapper).toMatchSnapshot();
}
});

test('hidden if hide include confirmSignIn', () => {
const wrapper = shallow(<ConfirmSignIn/>);
wrapper.setProps({
authState: acceptedStates[0],
hide: [ConfirmSignIn]
});
expect(wrapper).toMatchSnapshot();
});

});

describe('confirm test', () => {
test('user with challengeName SOFTWARE_TOKEN_MFA', async () => {
const wrapper = shallow(<ConfirmSignIn/>);

const spyon = jest.spyOn(Auth, 'confirmSignIn').mockImplementationOnce(() => {
return Promise.resolve();
});

wrapper.setProps({
authState: acceptedStates[0],
theme: AmplifyTheme,
authData: {
user: {
challengeName: 'SOFTWARE_TOKEN_MFA'
}
}
});

const confirmSignIn = wrapper.instance();

await confirmSignIn.confirm();

expect(spyon).toBeCalled();

spyon.mockClear();
});
});

describe('normal case', () => {
test('simulate clicking confirm button', async () => {
const spyon = jest.spyOn(Auth, 'confirmSignIn')
.mockImplementation((user, code) => {
Expand Down Expand Up @@ -83,19 +136,4 @@ describe('ConfirmSignIn', () => {
spyon2.mockClear();
});
});

describe('null case with other authState', () => {
test('render corrently', () => {
const wrapper = shallow(<ConfirmSignIn/>);

for (var i = 0; i < deniedStates.length; i += 1){
wrapper.setProps({
authState: deniedStates[i],
theme: AmplifyTheme
});

expect(wrapper).toMatchSnapshot();
}
});
});
})
13 changes: 10 additions & 3 deletions packages/aws-amplify-react/__tests__/Auth/FederatedSignIn-test.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,20 @@
import React from 'react';
import FederatedSignIn, { FederatedButtons } from '../../src/Auth/FederatedSignIn';
import { Auth } from 'aws-amplify';

const spyon = jest.spyOn(Auth, 'configure').mockImplementation(() => {
return {
hostedUIOptions: {}
}
})

describe('FederatedSignIn test', () => {
describe('render test', () => {
test('render with correct authState', () => {
const wrapper = shallow(<FederatedSignIn/>);

wrapper.setProps({
federated: true,
federated: {},
authState: 'signIn',
onStateChange: jest.fn()
});
Expand All @@ -18,7 +25,7 @@ describe('FederatedSignIn test', () => {
const wrapper = shallow(<FederatedSignIn/>);

wrapper.setProps({
federated: true,
federated: {},
authState: 'signedIn',
onStateChange: jest.fn()
});
Expand All @@ -29,7 +36,7 @@ describe('FederatedSignIn test', () => {
const wrapper = shallow(<FederatedSignIn/>);

wrapper.setProps({
federated: false,
federated: undefined,
authState: 'signIn',
onStateChange: jest.fn()
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,15 @@ describe('forgotPassword', () => {
}
});

test('hidden if hide include ForgotPassword', () => {
const wrapper = shallow(<ForgotPassword/>);
wrapper.setProps({
authState: acceptedStates[0],
hide: [ForgotPassword]
});
expect(wrapper).toMatchSnapshot();
});

test('simulating clicking submit', async () => {
const spyon = jest.spyOn(Auth, 'forgotPasswordSubmit')
.mockImplementationOnce(() => {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`withOAuth test render test render correctly 1`] = `
<MockComp
OAuthSignIn={[Function]}
/>
`;

exports[`withOAuth test render test render correctly with button 1`] = `
<Button
OAuthSignIn={[Function]}
/>
`;
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import React, { Component } from 'react';
import withOAuth, { OAuthButton } from '../../../src/Auth/Provider/withOAuth';
import { SignInButton, Button } from '../../../src/AmplifyUI';
import { Auth } from 'aws-amplify';

describe('withOAuth test', () => {
describe('render test', () => {
test('render correctly', () => {
const MockComp = class extends Component {
render() {
return <div />;
}
}

const Comp = withOAuth(MockComp);
const wrapper = shallow(<Comp/>);
expect(wrapper).toMatchSnapshot();
});

test('render correctly with button', () => {
const wrapper = shallow(<OAuthButton/>);
expect(wrapper).toMatchSnapshot();
});
});

describe('signIn test', () => {
test('happy case with connected response', () => {
const MockComp = class extends Component {
render() {
return <div />;
}
}

const spyon = jest.spyOn(Auth, 'configure').mockImplementationOnce(() => {
return {
hostedUIOptions: {
AppWebDomain: 'domain',
RedirectUriSignIn: 'redirectUriSignIn',
RedirectUriSignOut: 'redirectUriSignOut',
ResponseType: 'responseType'
},
userPoolWebClientId: 'userPoolWebClientId'
}
})
const Comp = withOAuth(MockComp);
const wrapper = shallow(<Comp/>);
const comp = wrapper.instance();

comp.signIn();

spyon.mockClear();
});
});
});
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`ConfirmSignIn normal case render correctly with Props confirmSignIn 1`] = `
exports[`ConfirmSignIn render test hidden if hide include confirmSignIn 1`] = `""`;

exports[`ConfirmSignIn render test render correctly with Props confirmSignIn 1`] = `
<FormSection
theme={
Object {
Expand Down Expand Up @@ -1706,18 +1708,18 @@ exports[`ConfirmSignIn normal case render correctly with Props confirmSignIn 1`]
</FormSection>
`;

exports[`ConfirmSignIn null case with other authState render corrently 1`] = `""`;
exports[`ConfirmSignIn render test render corrently with other authstate 1`] = `""`;

exports[`ConfirmSignIn null case with other authState render corrently 2`] = `""`;
exports[`ConfirmSignIn render test render corrently with other authstate 2`] = `""`;

exports[`ConfirmSignIn null case with other authState render corrently 3`] = `""`;
exports[`ConfirmSignIn render test render corrently with other authstate 3`] = `""`;

exports[`ConfirmSignIn null case with other authState render corrently 4`] = `""`;
exports[`ConfirmSignIn render test render corrently with other authstate 4`] = `""`;

exports[`ConfirmSignIn null case with other authState render corrently 5`] = `""`;
exports[`ConfirmSignIn render test render corrently with other authstate 5`] = `""`;

exports[`ConfirmSignIn null case with other authState render corrently 6`] = `""`;
exports[`ConfirmSignIn render test render corrently with other authstate 6`] = `""`;

exports[`ConfirmSignIn null case with other authState render corrently 7`] = `""`;
exports[`ConfirmSignIn render test render corrently with other authstate 7`] = `""`;

exports[`ConfirmSignIn null case with other authState render corrently 8`] = `""`;
exports[`ConfirmSignIn render test render corrently with other authstate 8`] = `""`;
Loading