-
Notifications
You must be signed in to change notification settings - Fork 554
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
Support new minimum password length parameter #1472
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
// Jest Snapshot v1, https://goo.gl/fbAQLP | ||
|
||
exports[`core/client/index initClient loads password policy 'excellent' correctly with a password_complexity_options option 1`] = ` | ||
Object { | ||
"minLength": 4, | ||
} | ||
`; | ||
|
||
exports[`core/client/index initClient loads password policy 'excellent' correctly without a password_complexity_options option 1`] = ` | ||
Object { | ||
"minLength": 10, | ||
} | ||
`; | ||
|
||
exports[`core/client/index initClient loads password policy 'fair' correctly with a password_complexity_options option 1`] = ` | ||
Object { | ||
"minLength": 4, | ||
} | ||
`; | ||
|
||
exports[`core/client/index initClient loads password policy 'fair' correctly without a password_complexity_options option 1`] = ` | ||
Object { | ||
"minLength": 8, | ||
} | ||
`; | ||
|
||
exports[`core/client/index initClient loads password policy 'good' correctly with a password_complexity_options option 1`] = ` | ||
Object { | ||
"minLength": 4, | ||
} | ||
`; | ||
|
||
exports[`core/client/index initClient loads password policy 'good' correctly without a password_complexity_options option 1`] = ` | ||
Object { | ||
"minLength": 8, | ||
} | ||
`; | ||
|
||
exports[`core/client/index initClient loads password policy 'low' correctly with a password_complexity_options option 1`] = ` | ||
Object { | ||
"minLength": 4, | ||
} | ||
`; | ||
|
||
exports[`core/client/index initClient loads password policy 'low' correctly without a password_complexity_options option 1`] = ` | ||
Object { | ||
"minLength": 6, | ||
} | ||
`; | ||
|
||
exports[`core/client/index initClient loads password policy 'none' correctly with a password_complexity_options option 1`] = ` | ||
Object { | ||
"minLength": 4, | ||
} | ||
`; | ||
|
||
exports[`core/client/index initClient loads password policy 'none' correctly without a password_complexity_options option 1`] = ` | ||
Object { | ||
"minLength": 1, | ||
} | ||
`; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
import Immutable from 'immutable'; | ||
import { initClient } from '../../../core/client'; | ||
|
||
describe('core/client/index', () => { | ||
describe('initClient', () => { | ||
['none', 'low', 'fair', 'good', 'excellent'].forEach(policy => { | ||
it(`loads password policy '${policy}' correctly without a password_complexity_options option`, () => { | ||
const client = { | ||
strategies: [ | ||
{ | ||
name: 'auth0', | ||
connections: [ | ||
{ | ||
name: 'Username-Password-Authentication', | ||
passwordPolicy: policy | ||
} | ||
] | ||
} | ||
] | ||
}; | ||
const result = initClient(Immutable.fromJS({}), client).toJS(); | ||
expect(result.client.connections.database[0].passwordPolicy.length).toMatchSnapshot(); | ||
}); | ||
it(`loads password policy '${policy}' correctly with a password_complexity_options option`, () => { | ||
const client = { | ||
strategies: [ | ||
{ | ||
name: 'auth0', | ||
connections: [ | ||
{ | ||
name: 'Username-Password-Authentication', | ||
passwordPolicy: policy, | ||
password_complexity_options: { min_length: 4 } | ||
} | ||
] | ||
} | ||
] | ||
}; | ||
const result = initClient(Immutable.fromJS({}), client).toJS(); | ||
expect(result.client.connections.database[0].passwordPolicy.length).toMatchSnapshot(); | ||
}); | ||
}); | ||
}); | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
import Immutable from 'immutable'; | ||
|
||
describe('field/password', () => { | ||
let passwordField; | ||
beforeEach(() => { | ||
jest.resetModules(); | ||
jest.mock('password-sheriff/lib/policy'); | ||
passwordField = require('field/password'); | ||
}); | ||
describe('validatePassword()', () => { | ||
it(`returns true when there is no policy`, () => { | ||
const value = passwordField.validatePassword('the-password'); | ||
expect(value).toBe(true); | ||
}); | ||
it(`validates password correctly when there is a policy`, () => { | ||
const model = { | ||
toJS: jest.fn() | ||
}; | ||
passwordField.validatePassword('the-password', model); | ||
const { mock } = require('password-sheriff/lib/policy').prototype.check; | ||
expect(mock.calls.length).toBe(1); | ||
expect(mock.calls[0][0]).toBe('the-password'); | ||
expect(model.toJS).toHaveBeenCalledTimes(1); | ||
}); | ||
}); | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
// Jest Snapshot v1, https://goo.gl/fbAQLP | ||
|
||
exports[`PasswordStrength validatePassword() validates password correctly with invalid password 1`] = `"<div class=\\"auth0-lock-password-strength animated fadeIn\\"><ul><li class=\\"\\"><span>At least 20 characters in length</span><!-- react-empty: 5 --></li></ul></div>"`; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
import React from 'react'; | ||
import { mount } from 'enzyme'; | ||
import PasswordStrength from '../../../../ui/input/password/password_strength'; | ||
|
||
describe('PasswordStrength', () => { | ||
beforeEach(() => { | ||
jest.resetModules(); | ||
}); | ||
describe('validatePassword()', () => { | ||
it(`validates password correctly with invalid password`, () => { | ||
const policy = { | ||
toJS: () => ({ | ||
length: { | ||
minLength: 20 | ||
} | ||
}) | ||
}; | ||
const messages = { foo: 'the-message' }; | ||
const wrapper = mount( | ||
<PasswordStrength policy={policy} password="the-password" messages={messages} /> | ||
); | ||
expect(wrapper.html()).toMatchSnapshot(); | ||
}); | ||
}); | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,8 +1,11 @@ | ||
import createPolicy from 'password-sheriff'; | ||
import PasswordPolicy from 'password-sheriff/lib/policy'; | ||
import { setField } from './index'; | ||
|
||
export function validatePassword(password, policy) { | ||
return createPolicy(policy).check(password); | ||
if (!policy) { | ||
return true; | ||
} | ||
return new PasswordPolicy(policy.toJS()).check(password); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Shouldn't this be safer, e.g. checking that if There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. policy is only undefined when it's a login, which we don't validate passwords. |
||
} | ||
|
||
export function setPassword(m, password, policy) { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,12 +1,12 @@ | ||
import PropTypes from 'prop-types'; | ||
import React from 'react'; | ||
import createPolicy from 'password-sheriff'; | ||
import PasswordPolicy from 'password-sheriff/lib/policy'; | ||
import util from 'util'; | ||
|
||
export default class PasswordStrength extends React.Component { | ||
render() { | ||
const { password, policy, messages } = this.props; | ||
const analysis = createPolicy(policy).missing(password); | ||
const analysis = new PasswordPolicy(policy.toJS()).missing(password); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think the same applies here There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this only runs on signup, so we're fine |
||
// TODO: add a component for fadeIn / fadeOut animations? | ||
const className = | ||
'auth0-lock-password-strength animated ' + (!analysis.verified ? 'fadeIn' : 'fadeOut'); | ||
|
@@ -39,7 +39,7 @@ export default class PasswordStrength extends React.Component { | |
PasswordStrength.propTypes = { | ||
messages: PropTypes.object.isRequired, | ||
password: PropTypes.string.isRequired, | ||
policy: PropTypes.oneOf(['none', 'low', 'fair', 'good', 'excellent']).isRequired | ||
policy: PropTypes.object.isRequired | ||
}; | ||
|
||
PasswordStrength.defaultProps = { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd trust more on password-sheriff than this repo. Sheriff already defines them here: https://github.com/auth0/password-sheriff/blob/4a17c9cba614ed8b75affc7c53ff0d4ba31a5b30/index.js. If this is not possible, then please copy that file and keep it here on this repo.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
our change password widget also uses this repo. This is fine