Skip to content

Commit

Permalink
query string parsing and customChallenge Cognito response case (aws-a…
Browse files Browse the repository at this point in the history
…mplify#3608)

* query string parsing and customChallenge Cognito response case

* checking for metadata from cognito response

* unit tests for react and vue
  • Loading branch information
haverchuck authored and T.J. Leing committed Jul 19, 2019
1 parent 3f32599 commit fc0294b
Show file tree
Hide file tree
Showing 9 changed files with 131 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,9 @@ const template = `
(usernameFieldChanged)="onUsernameFieldChanged($event)"
></amplify-auth-username-field-core>
<div class="amplify-form-row amplify-signin-password">
<label class="amplify-input-label" for="passwordField">{{ this.amplifyService.i18n().get('Password *') }}</label>
<label class="amplify-input-label" for="passwordField">
{{ this.amplifyService.i18n().get('Password *') }}
</label>
<input #passwordField
(keyup)="setPassword(passwordField.value)"
(keyup.enter)="onSignIn()"
Expand All @@ -42,11 +44,13 @@ const template = `
placeholder="{{ this.amplifyService.i18n().get('Enter your password') }}"
data-test="${auth.signIn.passwordInput}"
/>
<span class="amplify-form-action" *ngIf="!shouldHide('ForgotPassword')">{{ this.amplifyService.i18n().get('Forgot Password?') }}
<a class="amplify-form-link"
<span class="amplify-form-action" *ngIf="!shouldHide('ForgotPassword')">
{{ this.amplifyService.i18n().get('Forgot Password?') }}
<a class="amplify-form-link"
(click)="onForgotPassword()"
data-test="${auth.signIn.forgotPasswordLink}"
>{{ this.amplifyService.i18n().get('Reset your password') }}</a></span>
>{{ this.amplifyService.i18n().get('Reset your password') }}</a>
</span>
</div>
<div class="amplify-form-actions">
<div class="amplify-form-cell-right">
Expand Down Expand Up @@ -121,7 +125,10 @@ export class SignInComponentCore implements OnInit {
this._show = includes(['signIn', 'signedOut', 'signedUp'], authState.state);
this.username = authState.user? authState.user.username || '' : '';
this.email = authState.user? authState.user.email || '' : '';
this.country_code = authState.user && authState.user.country_code? authState.user.country_code : this.country_code;
this.country_code = authState.user &&
authState.user.country_code ?
authState.user.country_code :
this.country_code;
this.local_phone_number = authState.user? authState.user.local_phone_number || '' : '';
}

Expand Down Expand Up @@ -156,6 +163,12 @@ export class SignInComponentCore implements OnInit {
this.amplifyService.setAuthState({ state: 'confirmSignIn', user });
} else if (user['challengeName'] === 'NEW_PASSWORD_REQUIRED') {
this.amplifyService.setAuthState({ state: 'requireNewPassword', user });
} else if (
user['challengeName'] === 'CUSTOM_CHALLENGE' &&
user.challengeParam &&
user.challengeParam.trigger === 'true'
) {
this.amplifyService.setAuthState({ state: 'customConfirmSignIn', user });
} else {
this.amplifyService.setAuthState({ state: 'signedIn', user });
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ const template = `
#usernameField
class="amplify-form-input"
type="text"
value="{{this.username}}"
placeholder="{{ this.amplifyService.i18n().get(this.getPlaceholder()) }}"
(keyup)="setUsername($event.target.value)"
data-test="${auth.genericAttrs.usernameInput}"
Expand All @@ -58,6 +59,7 @@ const template = `
export class UsernameFieldComponentCore implements OnInit {
_usernameAttributes : string = UsernameAttributes.USERNAME;
_placeholder : string = '';
username: string;

constructor(@Inject(AmplifyService) protected amplifyService: AmplifyService) {
this.onPhoneFieldChanged = this.onPhoneFieldChanged.bind(this);
Expand All @@ -82,7 +84,19 @@ export class UsernameFieldComponentCore implements OnInit {
@Output()
usernameFieldChanged: EventEmitter<UsernameFieldOutput> = new EventEmitter<UsernameFieldOutput>();

ngOnInit() {}
ngOnInit() {
if (window &&
window.location &&
window.location.search &&
this._usernameAttributes !== 'email' &&
this._usernameAttributes !== 'phone_number'
) {
const searchParams = new URLSearchParams(window.location.search);
const username = searchParams ? searchParams.get('username') : undefined;
this.setUsername(username);
this.username = username;
}
}

ngOnDestroy() {}

Expand Down
52 changes: 51 additions & 1 deletion packages/aws-amplify-react/__tests__/Auth/SignIn-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ import { Header, Footer, Input, Button } from '../../src/Amplify-UI/Amplify-UI-C
const acceptedStates = [
'signIn',
'signedUp',
'signedOut'
'signedOut',
'customConfirmSignIn'
];

const deniedStates = [
Expand Down Expand Up @@ -99,6 +100,55 @@ describe('SignIn', () => {
spyon_changeState.mockClear();
});

test('when clicking signIn and trigger-based custom auth challenge present required', async () => {
const wrapper = shallow(<SignIn/>);
wrapper.setProps({
authState: 'signIn',
theme: AmplifyTheme
});

const spyon = jest.spyOn(Auth, 'signIn')
.mockImplementationOnce((user, password) => {
return new Promise((res, rej) => {
res({
challengeName: 'CUSTOM_CHALLENGE',
challengeParam: { trigger: 'true' }
});
});
});

const spyon_changeState = jest.spyOn(wrapper.instance(), 'changeState');

const event_username = {
target: {
name: 'username',
value: 'user1'
}
};
const event_password = {
target: {
name: 'password',
value: 'abc'
}
};

wrapper.find(Input).at(0).simulate('change', event_username);
wrapper.find(Input).at(1).simulate('change', event_password);
wrapper.find('form').at(0).simulate('submit', fakeEvent);

await Promise.resolve();

expect(spyon.mock.calls.length).toBe(1);
expect(spyon.mock.calls[0][0]).toBe(event_username.target.value);
expect(spyon.mock.calls[0][1]).toBe(event_password.target.value);

expect(spyon_changeState).toBeCalled();
expect(spyon_changeState.mock.calls[0][0]).toBe('customConfirmSignIn');

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

test('when clicking signIn and user session null, need verification of email and phone', async () => {
const wrapper = shallow(<SignIn/>);
wrapper.setProps({
Expand Down
6 changes: 6 additions & 0 deletions packages/aws-amplify-react/src/Auth/AuthPiece.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -87,10 +87,16 @@ export default class AuthPiece extends React.Component {
<PhoneField theme={theme} onChangeText={this.onPhoneNumberChanged}/>
);
} else {
let value;
if (window && window.location && window.search) {
const searchParams = new URLSearchParams(window.location.search);
value = searchParams ? searchParams.get('username') : undefined
}
return (
<FormField theme={theme}>
<InputLabel theme={theme}>{I18n.get(this.getUsernameLabel())} *</InputLabel>
<Input
value={value}
autoFocus
placeholder={I18n.get('Enter your username')}
theme={theme}
Expand Down
6 changes: 6 additions & 0 deletions packages/aws-amplify-react/src/Auth/SignIn.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,12 @@ export default class SignIn extends AuthPiece {
} else if (user.challengeName === 'MFA_SETUP') {
logger.debug('TOTP setup', user.challengeParam);
this.changeState('TOTPSetup', user);
} else if (user.challengeName === 'CUSTOM_CHALLENGE' &&
user.challengeParam &&
user.challengeParam.trigger === 'true'
) {
logger.debug('custom challenge', user.challengeParam);
this.changeState('customConfirmSignIn', user);
} else {
this.checkContact(user);
}
Expand Down
5 changes: 4 additions & 1 deletion packages/aws-amplify-vue/__mocks__/Amplify.mocks.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,10 @@ module.exports = {
resendSignUp: jest.fn(() => Promise.resolve({})),
setPreferredMFA: jest.fn(() => Promise.resolve({})),
setupTOTP: jest.fn(() => Promise.resolve('gibberish')),
signIn: jest.fn(() => Promise.resolve({})),
signIn: jest.fn(() => Promise.resolve({
challengeName: 'CUSTOM_CHALLENGE',
challengeParam: { trigger: 'true' },
})),
signOut: jest.fn(() => Promise.resolve({})),
signUp: jest.fn(() => Promise.resolve({})),
verifiedContact: jest.fn(() => Promise.resolve({})),
Expand Down
17 changes: 17 additions & 0 deletions packages/aws-amplify-vue/__tests__/SignIn.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import AmplifyPlugin from '../src/plugins/AmplifyPlugin';
import * as AmplifyMocks from '../__mocks__/Amplify.mocks';
/* eslint-enable */


Vue.use(AmplifyPlugin, AmplifyMocks);

describe('SignIn', () => {
Expand Down Expand Up @@ -69,10 +70,26 @@ describe('SignIn', () => {
expect(wrapper.vm.options.header).toEqual('i18n Sign in to your account');
expect(wrapper.vm.options.username).toEqual('');
});

it('...have default options', () => {
expect(wrapper.vm.options.header).toEqual('i18n Sign in to your account');
expect(wrapper.vm.options.username).toEqual('');
});

it('...should call Auth.signIn when signIn function is called', () => {
wrapper.vm.signIn();
expect(wrapper.vm.$Amplify.Auth.signIn).toHaveBeenCalledTimes(1);
});
it('...should emit customConfirmSignIn state when signIn function is called and response indicates a custom challenge', async () => {
let customTestState = 0;
AmplifyEventBus.$on('authState', (val) => {
if (val === 'customConfirmSignIn') {
customTestState = 3;
}
});
await wrapper.vm.signIn();
expect(customTestState).toEqual(3);
});
it('...should emit authState when forgot method called', () => {
testState = 0;
AmplifyEventBus.$on('authState', (val) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,12 @@ export default {
} else if (data.challengeName === 'MFA_SETUP') {
AmplifyEventBus.$emit('localUser', data);
return AmplifyEventBus.$emit('authState', 'setMfa');
} else if (data.challengeName === 'CUSTOM_CHALLENGE' &&
data.challengeParam &&
data.challengeParam.trigger === 'true'
) {
AmplifyEventBus.$emit('localUser', data);
return AmplifyEventBus.$emit('authState', 'customConfirmSignIn')
} else {
return AmplifyEventBus.$emit('authState', 'signedIn')
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,14 @@ export default {
auth,
}
},
mounted: function() {
if (window && window.location && window.location.search) {
const searchParams = new URLSearchParams(window.location.search);
const usernameParam = searchParams ? searchParams.get('username') : this.username;
this.username = usernameParam;
this.$emit('username-field-changed', {usernameField: 'username', username: usernameParam});
}
},
computed: {
shouldRenderEmailField() {
return this.usernameAttributes === 'email';
Expand Down

0 comments on commit fc0294b

Please sign in to comment.