@riao/authn-password 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md ADDED
@@ -0,0 +1 @@
1
+ # authn-password - Changelog
package/LICENSE.md ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2022 authn-password and others
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,145 @@
1
+ # @riao/authn-password
2
+
3
+ A TypeScript library that provides password-based authentication for the RIAO Identity and Access Management (IAM) framework. This driver implements secure password hashing and verification using bcrypt.
4
+
5
+ ## Features
6
+
7
+ - **Secure Password Hashing**: Uses bcrypt for secure password hashing with configurable salt rounds
8
+ - **Principal Management**: Create and manage user principals with associated passwords
9
+ - **Authentication**: Authenticate users with login credentials and passwords
10
+ - **Flexible Hash Implementation**: Supports custom hash implementations via the `Hash` interface
11
+ - **Database Agnostic**: Works with any database supported by the RIAO DBAL (Database Abstraction Layer)
12
+ - **TypeScript Support**: Full TypeScript support with type safety
13
+
14
+ ## Installation
15
+
16
+ ```bash
17
+ npm install @riao/authn-password @riao/iam @riao/dbal
18
+ npm install --save-dev @riao/cli
19
+ ```
20
+
21
+ ## Database Migrations
22
+
23
+ This driver requires the IAM password table to be created in your database. You can use the provided migrations:
24
+
25
+ ```bash
26
+ npx riao migration:create import-iam-tables
27
+ ```
28
+
29
+ Then, add the `AuthenticationPasswordMigrations` to your migration runner:
30
+
31
+ `database/main/migrations/1234567890-import-iam-tables.ts`
32
+ ```typescript
33
+ import { AuthenticationPasswordMigrations } from 'authn-password';
34
+
35
+ export default AuthenticationPasswordMigrations;
36
+ ```
37
+
38
+ ## Quick Start
39
+
40
+ ### Basic Usage
41
+
42
+ ```typescript
43
+ import { PasswordAuthentication } from '@riao/authn-password';
44
+ import { Principal } from '@riao/iam/auth';
45
+ import { Database } from '@riao/dbal';
46
+
47
+ // Define your user interface
48
+ interface User extends Principal {
49
+ login: string;
50
+ }
51
+
52
+ // Create an authentication service class
53
+ class UserAuthentication extends PasswordAuthentication<User> {}
54
+
55
+ // Initialize with your database
56
+ const db = new YourDatabase();
57
+ await db.init();
58
+ await db.connect();
59
+
60
+ const authService = new UserAuthentication({ db });
61
+
62
+ // Create a new user with a password
63
+ const userId = await authService.createPrincipal({
64
+ login: 'john.doe',
65
+ type: 'user',
66
+ name: 'John Doe',
67
+ password: 'securePassword123',
68
+ });
69
+
70
+ // Authenticate a user
71
+ const user = await authService.authenticate({
72
+ login: 'john.doe',
73
+ password: 'securePassword123',
74
+ });
75
+
76
+ if (user) {
77
+ console.log(`Welcome ${user.name}!`);
78
+ }
79
+ else {
80
+ console.log('Authentication failed');
81
+ }
82
+ ```
83
+
84
+ ## API Reference
85
+
86
+ ### PasswordAuthentication<TPrincipal>
87
+
88
+ Abstract class that extends `Authentication<TPrincipal>` and adds password-based authentication.
89
+
90
+ #### Constructor Options
91
+
92
+ ```typescript
93
+ interface PasswordAuthenticationOptions extends AuthOptions {
94
+ hash?: Hash; // Optional custom hash implementation (defaults to bcrypt)
95
+ }
96
+ ```
97
+
98
+ #### Methods
99
+
100
+ - **createPrincipal(principal)**: Creates a new principal with a hashed password
101
+ - Parameters: Principal data with `password` field
102
+ - Returns: Principal ID
103
+
104
+ - **authenticate(credentials)**: Authenticates a user with login and password
105
+ - Parameters: Object with `login` and `password` fields
106
+ - Returns: Principal object if successful, null if authentication fails
107
+
108
+ - **passwordsRepo**: Query repository for accessing password records directly
109
+
110
+ ### Password Record Schema
111
+
112
+ Passwords are stored in the `iam_passwords` table:
113
+
114
+ ```typescript
115
+ interface Password {
116
+ id?: string;
117
+ principal_id: string; // Foreign key to principal
118
+ password_hash: string; // Bcrypt hashed password
119
+ deactivate_timestamp?: string;
120
+ create_timestamp?: string;
121
+ }
122
+ ```
123
+
124
+ ## Configuration
125
+
126
+ ### Custom Hash Implementation
127
+
128
+ You can provide a custom hash implementation:
129
+
130
+ ```typescript
131
+ import { Hash } from '@riao/iam/hash';
132
+
133
+ class CustomHash extends Hash {
134
+ // Implement your custom hashing logic
135
+ }
136
+
137
+ const authService = new UserAuthentication({
138
+ db,
139
+ hash: new CustomHash(),
140
+ });
141
+ ```
142
+
143
+ ## Contributing & Development
144
+
145
+ See [contributing.md](docs/contributing/contributing.md) for information on how to develop or contribute to this project!
@@ -0,0 +1,5 @@
1
+ import { Migration } from '@riao/dbal';
2
+ import { AuthMigrations } from '@riao/iam/auth/auth-migrations';
3
+ export declare class AuthenticationPasswordMigrations extends AuthMigrations {
4
+ getMigrations(): Promise<Record<string, typeof Migration<any>>>;
5
+ }
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.AuthenticationPasswordMigrations = void 0;
4
+ const auth_migrations_1 = require("@riao/iam/auth/auth-migrations");
5
+ const _001_create_passwords_table_1 = require("./migrations/001-create-passwords-table");
6
+ class AuthenticationPasswordMigrations extends auth_migrations_1.AuthMigrations {
7
+ async getMigrations() {
8
+ return {
9
+ ...(await super.getMigrations()),
10
+ 'create-passwords-table': _001_create_passwords_table_1.CreatePasswordsTable,
11
+ };
12
+ }
13
+ }
14
+ exports.AuthenticationPasswordMigrations = AuthenticationPasswordMigrations;
15
+ //# sourceMappingURL=authentication-password-migrations.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"authentication-password-migrations.js","sourceRoot":"","sources":["../../src/authentication-password-migrations.ts"],"names":[],"mappings":";;;AACA,oEAAgE;AAChE,yFAA+E;AAE/E,MAAa,gCAAiC,SAAQ,gCAAc;IAC1D,KAAK,CAAC,aAAa;QAI3B,OAAO;YACN,GAAG,CAAC,MAAM,KAAK,CAAC,aAAa,EAAE,CAAC;YAChC,wBAAwB,EAAE,kDAAoB;SAC9C,CAAC;IACH,CAAC;CACD;AAVD,4EAUC"}
@@ -0,0 +1,20 @@
1
+ import { DatabaseRecordId, QueryRepository } from '@riao/dbal';
2
+ import { Hash } from '@riao/iam/hash';
3
+ import { Principal } from '@riao/iam/auth';
4
+ import { Authentication } from '@riao/iam/authentication';
5
+ import { AuthOptions } from '@riao/iam/auth/auth';
6
+ import { Password } from './password';
7
+ export interface PasswordAuthenticationOptions extends AuthOptions {
8
+ hash?: Hash;
9
+ }
10
+ export declare abstract class PasswordAuthentication<TPrincipal extends Principal> extends Authentication<TPrincipal> {
11
+ passwordsRepo: QueryRepository<Password>;
12
+ protected hash: Hash;
13
+ constructor(options: PasswordAuthenticationOptions);
14
+ createPrincipal(principal: Omit<TPrincipal, 'id' | 'create_timestamp'> & {
15
+ password: string;
16
+ }): Promise<DatabaseRecordId>;
17
+ authenticate(credentials: Partial<TPrincipal & {
18
+ password: string;
19
+ }>): Promise<TPrincipal | null>;
20
+ }
@@ -0,0 +1,50 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PasswordAuthentication = void 0;
4
+ const hash_1 = require("@riao/iam/hash");
5
+ const authentication_1 = require("@riao/iam/authentication");
6
+ class PasswordAuthentication extends authentication_1.Authentication {
7
+ passwordsRepo;
8
+ hash;
9
+ constructor(options) {
10
+ super(options);
11
+ this.hash = options.hash ?? new hash_1.Hash();
12
+ this.passwordsRepo = options.db.getQueryRepository({
13
+ table: 'iam_passwords',
14
+ identifiedBy: 'id',
15
+ });
16
+ }
17
+ async createPrincipal(principal) {
18
+ const hash = await this.hash.make(principal.password);
19
+ delete principal.password;
20
+ const principalId = await super.createPrincipal(principal);
21
+ await this.passwordsRepo.insertOne({
22
+ record: {
23
+ principal_id: principalId,
24
+ password_hash: hash,
25
+ },
26
+ });
27
+ return principalId;
28
+ }
29
+ async authenticate(credentials) {
30
+ const principal = await this.findActivePrincipal({
31
+ where: {
32
+ login: credentials.login,
33
+ },
34
+ });
35
+ if (!principal) {
36
+ return null;
37
+ }
38
+ const passwordRecord = await this.passwordsRepo.findOne({
39
+ where: { principal_id: principal.id, deactivate_timestamp: null },
40
+ orderBy: { create_timestamp: 'DESC' },
41
+ });
42
+ if (!passwordRecord) {
43
+ return null;
44
+ }
45
+ const isValid = await this.hash.check(credentials.password, passwordRecord?.password_hash);
46
+ return isValid ? principal : null;
47
+ }
48
+ }
49
+ exports.PasswordAuthentication = PasswordAuthentication;
50
+ //# sourceMappingURL=authentication-password.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"authentication-password.js","sourceRoot":"","sources":["../../src/authentication-password.ts"],"names":[],"mappings":";;;AACA,yCAAsC;AAEtC,6DAA0D;AAQ1D,MAAsB,sBAEpB,SAAQ,+BAA0B;IAC5B,aAAa,CAA4B;IAEtC,IAAI,CAAO;IAErB,YAAmB,OAAsC;QACxD,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,OAAO,CAAC,IAAI,IAAI,IAAI,WAAI,EAAE,CAAC;QACvC,IAAI,CAAC,aAAa,GAAG,OAAO,CAAC,EAAE,CAAC,kBAAkB,CAAW;YAC5D,KAAK,EAAE,eAAe;YACtB,YAAY,EAAE,IAAI;SAClB,CAAC,CAAC;IACJ,CAAC;IAEe,KAAK,CAAC,eAAe,CACpC,SAEC;QAED,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;QACtD,OAAQ,SAAmC,CAAC,QAAQ,CAAC;QAErD,MAAM,WAAW,GAAG,MAAM,KAAK,CAAC,eAAe,CAAC,SAAS,CAAC,CAAC;QAE3D,MAAM,IAAI,CAAC,aAAa,CAAC,SAAS,CAAC;YAClC,MAAM,EAAE;gBACP,YAAY,EAAE,WAAqB;gBACnC,aAAa,EAAE,IAAI;aACnB;SACD,CAAC,CAAC;QAEH,OAAO,WAAW,CAAC;IACpB,CAAC;IAEM,KAAK,CAAC,YAAY,CACxB,WAAuD;QAEvD,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,mBAAmB,CAAC;YAChD,KAAK,EAAc;gBAClB,KAAK,EAAE,WAAW,CAAC,KAAK;aACxB;SACD,CAAC,CAAC;QAEH,IAAI,CAAC,SAAS,EAAE,CAAC;YAChB,OAAO,IAAI,CAAC;QACb,CAAC;QAED,MAAM,cAAc,GAAG,MAAM,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC;YACvD,KAAK,EAAE,EAAE,YAAY,EAAE,SAAS,CAAC,EAAE,EAAE,oBAAoB,EAAE,IAAI,EAAE;YACjE,OAAO,EAAE,EAAE,gBAAgB,EAAE,MAAM,EAAE;SACrC,CAAC,CAAC;QAEH,IAAI,CAAC,cAAc,EAAE,CAAC;YACrB,OAAO,IAAI,CAAC;QACb,CAAC;QAED,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,KAAK,CACpC,WAAW,CAAC,QAAkB,EAC9B,cAAc,EAAE,aAAuB,CACvC,CAAC;QAEF,OAAO,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC;IACnC,CAAC;CACD;AAjED,wDAiEC"}
package/index.d.ts ADDED
@@ -0,0 +1 @@
1
+ export { PasswordAuthentication } from './authentication-password';
package/index.js ADDED
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PasswordAuthentication = void 0;
4
+ var authentication_password_1 = require("./authentication-password");
5
+ Object.defineProperty(exports, "PasswordAuthentication", { enumerable: true, get: function () { return authentication_password_1.PasswordAuthentication; } });
6
+ //# sourceMappingURL=index.js.map
package/index.js.map ADDED
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";;;AAAA,qEAAmE;AAA1D,iIAAA,sBAAsB,OAAA"}
@@ -0,0 +1,5 @@
1
+ import { Migration } from '@riao/dbal';
2
+ export declare class CreatePasswordsTable extends Migration {
3
+ up(): Promise<void>;
4
+ down(): Promise<void>;
5
+ }
@@ -0,0 +1,38 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.CreatePasswordsTable = void 0;
4
+ const column_pack_1 = require("@riao/dbal/column-pack");
5
+ const dbal_1 = require("@riao/dbal");
6
+ class CreatePasswordsTable extends dbal_1.Migration {
7
+ async up() {
8
+ await this.ddl.createTable({
9
+ name: 'iam_passwords',
10
+ columns: [
11
+ column_pack_1.UUIDKeyColumn,
12
+ {
13
+ name: 'principal_id',
14
+ type: dbal_1.ColumnType.UUID,
15
+ fk: {
16
+ referencesTable: 'iam_principals',
17
+ referencesColumn: 'id',
18
+ onDelete: 'CASCADE',
19
+ },
20
+ },
21
+ { ...column_pack_1.PasswordColumn, name: 'password_hash' },
22
+ column_pack_1.CreateTimestampColumn,
23
+ {
24
+ name: 'deactivate_timestamp',
25
+ type: dbal_1.ColumnType.TIMESTAMP,
26
+ required: false,
27
+ },
28
+ ],
29
+ });
30
+ }
31
+ async down() {
32
+ await this.ddl.dropTable({
33
+ tables: 'iam_passwords',
34
+ });
35
+ }
36
+ }
37
+ exports.CreatePasswordsTable = CreatePasswordsTable;
38
+ //# sourceMappingURL=001-create-passwords-table.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"001-create-passwords-table.js","sourceRoot":"","sources":["../../../src/migrations/001-create-passwords-table.ts"],"names":[],"mappings":";;;AAAA,wDAIgC;AAChC,qCAAmD;AAEnD,MAAa,oBAAqB,SAAQ,gBAAS;IACzC,KAAK,CAAC,EAAE;QAChB,MAAM,IAAI,CAAC,GAAG,CAAC,WAAW,CAAC;YAC1B,IAAI,EAAE,eAAe;YACrB,OAAO,EAAE;gBACR,2BAAa;gBACb;oBACC,IAAI,EAAE,cAAc;oBACpB,IAAI,EAAE,iBAAU,CAAC,IAAI;oBACrB,EAAE,EAAE;wBACH,eAAe,EAAE,gBAAgB;wBACjC,gBAAgB,EAAE,IAAI;wBACtB,QAAQ,EAAE,SAAS;qBACnB;iBACD;gBACD,EAAE,GAAG,4BAAc,EAAE,IAAI,EAAE,eAAe,EAAE;gBAC5C,mCAAqB;gBACrB;oBACC,IAAI,EAAE,sBAAsB;oBAC5B,IAAI,EAAE,iBAAU,CAAC,SAAS;oBAC1B,QAAQ,EAAE,KAAK;iBACf;aACD;SACD,CAAC,CAAC;IACJ,CAAC;IAEQ,KAAK,CAAC,IAAI;QAClB,MAAM,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC;YACxB,MAAM,EAAE,eAAe;SACvB,CAAC,CAAC;IACJ,CAAC;CACD;AA/BD,oDA+BC"}
package/package.json ADDED
@@ -0,0 +1,42 @@
1
+ {
2
+ "name": "@riao/authn-password",
3
+ "version": "1.0.0",
4
+ "description": "Password driver for Riao",
5
+ "typescript-template": {
6
+ "base": "1.0.1",
7
+ "jasmine": "1.0.0",
8
+ "library": "1.0.0"
9
+ },
10
+ "scripts": {},
11
+ "dependencies": {
12
+ "@riao/dbal": "^3.8.0",
13
+ "@riao/iam": "^3.0.0",
14
+ "bcrypt": "^6.0.0"
15
+ },
16
+ "repository": {
17
+ "type": "git",
18
+ "url": "git+https://github.com/authn-password/authn-password.git"
19
+ },
20
+ "author": "authn-password",
21
+ "license": "MIT",
22
+ "bugs": {
23
+ "url": "https://github.com/authn-password/authn-password/issues"
24
+ },
25
+ "homepage": "https://github.com/authn-password/authn-password#readme",
26
+ "keywords": [
27
+ "authn",
28
+ "authentication",
29
+ "password",
30
+ "riao",
31
+ "bcrypt",
32
+ "riao-driver",
33
+ "riao-authn",
34
+ "riao-authn-driver",
35
+ "authentication-driver",
36
+ "authn-driver",
37
+ "authn-password",
38
+ "authn-password-driver"
39
+ ],
40
+ "main": "index.js",
41
+ "types": "index.d.ts"
42
+ }
package/password.d.ts ADDED
@@ -0,0 +1,7 @@
1
+ export interface Password {
2
+ id: string;
3
+ principal_id: string;
4
+ password_hash: string;
5
+ create_timestamp: Date;
6
+ deactivate_timestamp?: Date | null;
7
+ }
package/password.js ADDED
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=password.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"password.js","sourceRoot":"","sources":["../../src/password.ts"],"names":[],"mappings":""}