diff --git a/examples/access-control-migration/data/db.json b/examples/access-control-migration/data/db.json index 12795d1886f6..f692036839b0 100644 --- a/examples/access-control-migration/data/db.json +++ b/examples/access-control-migration/data/db.json @@ -7,7 +7,7 @@ }, "models": { "Project": { - "1": "{\"id\":1,\"name\":\"project1\",\"balance\":0,\"ownerId\":1}", + "1": "{\"id\":1,\"name\":\"project1\",\"balance\":90,\"ownerId\":1}", "2": "{\"id\":2,\"name\":\"project2\",\"balance\":0,\"ownerId\":2}" }, "Team": { @@ -20,9 +20,9 @@ "3": "{\"id\":3,\"username\":\"Bob\",\"email\":\"bob@projects.com\"}" }, "UserCredentials": { - "1": "{\"password\":\"opensesame\",\"userId\":1,\"id\":1}", - "2": "{\"password\":\"opensesame\",\"userId\":2,\"id\":2}", - "3": "{\"password\":\"opensesame\",\"userId\":3,\"id\":3}" + "1": "{\"password\":\"$2a$10$Yn1/fMOjW6A.CdH7Yxb7weVFYmkcQJQBaYaiRScS6sw7ty3aL4lHu\",\"userId\":1,\"id\":1}", + "2": "{\"password\":\"$2a$10$Yn1/fMOjW6A.CdH7Yxb7weVFYmkcQJQBaYaiRScS6sw7ty3aL4lHu\",\"userId\":2,\"id\":2}", + "3": "{\"password\":\"$2a$10$Yn1/fMOjW6A.CdH7Yxb7weVFYmkcQJQBaYaiRScS6sw7ty3aL4lHu\",\"userId\":3,\"id\":3}" } } } \ No newline at end of file diff --git a/examples/access-control-migration/package-lock.json b/examples/access-control-migration/package-lock.json index 054166a135c2..30a3d811a551 100644 --- a/examples/access-control-migration/package-lock.json +++ b/examples/access-control-migration/package-lock.json @@ -24,6 +24,11 @@ "js-tokens": "^4.0.0" } }, + "@types/bcryptjs": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/@types/bcryptjs/-/bcryptjs-2.4.2.tgz", + "integrity": "sha512-LiMQ6EOPob/4yUL66SZzu6Yh77cbzJFYll+ZfaPiPPFswtIlA/Fs1MzdKYA7JApHU49zQTbJGX3PDmCpIdDBRQ==" + }, "@types/eslint-visitor-keys": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/@types/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz", @@ -223,6 +228,11 @@ "tweetnacl": "^0.14.3" } }, + "bcryptjs": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-2.4.3.tgz", + "integrity": "sha1-mrVie5PmBiH/fNrF2pczAn3x0Ms=" + }, "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", diff --git a/examples/access-control-migration/package.json b/examples/access-control-migration/package.json index c7f63ccae230..3beb8e1d761c 100644 --- a/examples/access-control-migration/package.json +++ b/examples/access-control-migration/package.json @@ -47,6 +47,8 @@ "@loopback/rest-explorer": "^1.4.10", "@loopback/security": "^0.1.13", "@loopback/service-proxy": "^1.3.17", + "bcryptjs": "^2.4.3", + "@types/bcryptjs": "2.4.2", "casbin": "^3.1.0", "jsonwebtoken": "^8.5.1", "loopback-connector-rest": "^3.6.0", diff --git a/examples/access-control-migration/src/observers/sample.observer.ts b/examples/access-control-migration/src/observers/sample.observer.ts index bb201a392e45..44345005a04e 100644 --- a/examples/access-control-migration/src/observers/sample.observer.ts +++ b/examples/access-control-migration/src/observers/sample.observer.ts @@ -14,6 +14,7 @@ import * as _ from 'lodash'; import {ProjectRepository} from '../repositories/project.repository'; import {TeamRepository} from '../repositories/team.repository'; import {UserRepository} from '../repositories/user.repository'; +import {genSalt, hash} from 'bcryptjs'; /** * This class will be bound to the application as a `LifeCycleObserver` during @@ -49,14 +50,25 @@ export class SampleObserver implements LifeCycleObserver { } async createUsers(): Promise { + const hashedPassword = await this.hashPassword('opensesame', 10); const users = [ - {id: 1, username: 'John', email: 'john@doe.com', password: 'opensesame'}, - {id: 2, username: 'Jane', email: 'jane@doe.com', password: 'opensesame'}, + { + id: 1, + username: 'John', + email: 'john@doe.com', + password: hashedPassword, + }, + { + id: 2, + username: 'Jane', + email: 'jane@doe.com', + password: hashedPassword, + }, { id: 3, username: 'Bob', email: 'bob@projects.com', - password: 'opensesame', + password: hashedPassword, }, ]; @@ -89,4 +101,9 @@ export class SampleObserver implements LifeCycleObserver { await this.teamRepo.create(t); } } + + async hashPassword(password: string, rounds: number): Promise { + const salt = await genSalt(rounds); + return hash(password, salt); + } } diff --git a/examples/access-control-migration/src/services/user.service.ts b/examples/access-control-migration/src/services/user.service.ts index 2fe47e505d0f..ee94e9aaedff 100644 --- a/examples/access-control-migration/src/services/user.service.ts +++ b/examples/access-control-migration/src/services/user.service.ts @@ -3,12 +3,13 @@ // This file is licensed under the MIT License. // License text available at https://opensource.org/licenses/MIT -import {HttpErrors} from '@loopback/rest'; -import {UserRepository} from '../repositories/user.repository'; -import {User} from '../models/user.model'; import {UserService} from '@loopback/authentication'; -import {UserProfile, securityId} from '@loopback/security'; import {repository} from '@loopback/repository'; +import {HttpErrors} from '@loopback/rest'; +import {securityId, UserProfile} from '@loopback/security'; +import {compare} from 'bcryptjs'; +import {User} from '../models/user.model'; +import {UserRepository} from '../repositories/user.repository'; export type Credentials = { email: string; @@ -36,8 +37,11 @@ export class MyUserService implements UserService { if (!credentialsFound) { throw new HttpErrors.Unauthorized(invalidCredentialsError); } - // TBD: Hash password - const passwordMatched = credentialsFound.password === credentials.password; + + const passwordMatched = await compare( + credentials.password, + credentialsFound.password, + ); if (!passwordMatched) { throw new HttpErrors.Unauthorized(invalidCredentialsError);