Skip to content

Commit

Permalink
feature(#8676): added usernameMatch criteria to login methods to matc…
Browse files Browse the repository at this point in the history
…h signup (#8686)

This PR adds insensitive matching to the login step of dbAuth, this is
to match the matching we implemented previously in the register step.
For full details please see the bug
#8676
  • Loading branch information
ageddesi authored Jul 6, 2023
1 parent a9ef9b6 commit f5d1a1a
Show file tree
Hide file tree
Showing 5 changed files with 613 additions and 521 deletions.
8 changes: 7 additions & 1 deletion docs/docs/auth/dbauth.md
Original file line number Diff line number Diff line change
Expand Up @@ -253,14 +253,20 @@ This handler is invoked after the password has been successfully changed in the

### usernameMatch

This configuration allows you to perform a case insensitive check on a username at the point of user creation.
This configuration allows you to perform a case insensitive check on a username at the point of db check. You will need to provide the configuration of your choice for both signup and login.

```javascript
signup: {
usernameMatch: 'insensitive'
}
```

```javascript
login: {
usernameMatch: 'insensitive'
}
```

By default no setting is required. This is because each db has its own rules for enabling this feature. To enable please see the table below and pick the correct 'userMatchString' for your db of choice.

| DB | Default | usernameMatchString | notes |
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@
"ncp": "2.0.0",
"nodemon": "2.0.22",
"npm-packlist": "7.0.4",
"nx": "16.4.0",
"nx": "16.4.1",
"nx-cloud": "16.0.5",
"octokit": "2.1.0",
"ora": "5.4.1",
Expand Down
46 changes: 33 additions & 13 deletions packages/auth-providers/dbAuth/api/src/DbAuthHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,11 @@ interface LoginFlowOptions<TUser = Record<string | number, any>> {
* How long a user will remain logged in, in seconds
*/
expires: number

/**
* Allows the user to define if the UserCheck for their selected db provider should use case insensitive
*/
usernameMatch?: string
}

interface ResetPasswordFlowOptions<TUser = Record<string | number, any>> {
Expand Down Expand Up @@ -1223,11 +1228,16 @@ export class DbAuthHandler<
)
}

const usernameMatchFlowOption = (this.options.login as LoginFlowOptions)
?.usernameMatch
const findUniqueUserMatchCriteriaOptions =
this._getUserMatchCriteriaOptions(username, usernameMatchFlowOption)
let user

try {
// does user exist?
user = await this.dbAccessor.findUnique({
where: { [this.options.authFields.username]: username },
user = await this.dbAccessor.findFirst({
where: findUniqueUserMatchCriteriaOptions,
})
} catch (e) {
throw new DbAuthError.GenericError()
Expand Down Expand Up @@ -1296,19 +1306,10 @@ export class DbAuthHandler<
this._validateField('username', username) &&
this._validateField('password', password)
) {
// Each db provider has it owns rules for case insensitive comparison.
// We are checking if you have defined one for your db choice here
// https://www.prisma.io/docs/concepts/components/prisma-client/case-sensitivity
const usernameMatchFlowOption = (this.options.signup as SignupFlowOptions)
?.usernameMatch
const findUniqueUserMatchCriteriaOptions = !usernameMatchFlowOption
? { [this.options.authFields.username]: username }
: {
[this.options.authFields.username]: {
equals: username,
mode: usernameMatchFlowOption,
},
}
const findUniqueUserMatchCriteriaOptions =
this._getUserMatchCriteriaOptions(username, usernameMatchFlowOption)

const user = await this.dbAccessor.findFirst({
where: findUniqueUserMatchCriteriaOptions,
Expand Down Expand Up @@ -1439,4 +1440,23 @@ export class DbAuthHandler<
},
}
}

_getUserMatchCriteriaOptions(
username: string,
usernameMatchFlowOption: string | undefined
) {
// Each db provider has it owns rules for case insensitive comparison.
// We are checking if you have defined one for your db choice here
// https://www.prisma.io/docs/concepts/components/prisma-client/case-sensitivity
const findUniqueUserMatchCriteriaOptions = !usernameMatchFlowOption
? { [this.options.authFields.username]: username }
: {
[this.options.authFields.username]: {
equals: username,
mode: usernameMatchFlowOption,
},
}

return findUniqueUserMatchCriteriaOptions
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -884,6 +884,9 @@ describe('dbAuth', () => {
expect.assertions(1)
})
it('throws an error if username is not found', async () => {
delete options.signup.usernameMatch
delete options.login.usernameMatch

await createDbUser()
event.body = JSON.stringify({
username: 'missing@redwoodjs.com',
Expand Down Expand Up @@ -1026,6 +1029,58 @@ describe('dbAuth', () => {

expectLoggedInResponse(response)
})

it('login db check is called with insensitive string when user has provided one in LoginFlowOptions', async () => {
jest.clearAllMocks()
const spy = jest.spyOn(db.user, 'findFirst')

options.signup.usernameMatch = 'insensitive'
options.login.usernameMatch = 'insensitive'

await createDbUser()
event.body = JSON.stringify({
username: 'rob@redwoodjs.com',
password: 'password',
})

const dbAuth = new DbAuthHandler(event, context, options)

try {
await dbAuth.login()
} catch (e) {
expect(e).toBeInstanceOf(dbAuthError.UserNotFoundError)
}

return expect(spy).toHaveBeenCalledWith({
where: {
email: expect.objectContaining({ mode: 'insensitive' }),
},
})
})

it('login db check is not called with insensitive string when user has not provided one in LoginFlowOptions', async () => {
jest.clearAllMocks()
const spy = jest.spyOn(db.user, 'findFirst')

delete options.signup.usernameMatch
delete options.login.usernameMatch

await createDbUser()
event.body = JSON.stringify({
username: 'rob@redwoodjs.com',
password: 'password',
})

const dbAuth = new DbAuthHandler(event, context, options)

await dbAuth.login()

return expect(spy).not.toHaveBeenCalledWith({
where: {
email: expect.objectContaining({ mode: 'insensitive' }),
},
})
})
})

describe('logout', () => {
Expand Down
Loading

0 comments on commit f5d1a1a

Please sign in to comment.