diff --git a/lib/index.d.ts b/lib/index.d.ts index 6ed8f99..aee56ec 100644 --- a/lib/index.d.ts +++ b/lib/index.d.ts @@ -1230,22 +1230,36 @@ declare namespace Stardog { } type Action = + | 'ALL' | 'CREATE' | 'DELETE' - | 'READ' - | 'WRITE' + | 'EXECUTE' | 'GRANT' + | 'READ' | 'REVOKE' - | 'EXECUTE'; + | 'WRITE'; type ResourceType = - | 'db' - | 'user' - | 'role' + | '*' | 'admin' + | 'cache' + | 'cache-target' + | 'data-source' + | 'db' + | 'db-export' + | 'dbms-admin' + | 'entity-resolution' + | 'icv-constraints' | 'metadata' + | 'modeling' | 'named-graph' - | 'icv-constraints'; + | 'permission' + | 'role' + | 'role-assignment' + | 'sensitive-properties' + | 'stored-query' + | 'user' + | 'virtual-graph'; /** * Gets a list of users. @@ -1440,6 +1454,21 @@ declare namespace Stardog { params?: object ): Promise; + /** + * Checks if the current user has a specific permission. + * + * @param {Connection} conn the Stardog server connection + * @param {Action} action the action to check + * @param {ResourceType} resourceType the type of resource + * @param {string} resource the resource name + */ + function checkPermission( + conn: Connection, + action: Action, + resourceType: ResourceType, + resource: string + ): Promise; + /** * Specifies whether a user is a superuser. * diff --git a/lib/user/main.js b/lib/user/main.js index 0716483..1af7035 100644 --- a/lib/user/main.js +++ b/lib/user/main.js @@ -1,4 +1,5 @@ const { httpBody, httpMessage } = require('../response-transforms'); +const { encodeQueryString } = require('../utils'); const list = (conn, params) => { const headers = conn.headers(); @@ -162,6 +163,26 @@ const effectivePermissions = (conn, username, params) => { ).then(httpBody); }; +const checkPermission = (conn, action, resourceType, resource) => { + const headers = conn.headers(); + headers.set('Accept', 'application/json'); + const queryParams = { + action, + resource_type: resourceType, + resource, + }; + return fetch( + conn.request( + 'admin', + 'permissions', + `check${encodeQueryString(queryParams)}` + ), + { + headers, + } + ).then(httpBody); +}; + const superUser = (conn, username, params) => { const headers = conn.headers(); headers.set('Accept', 'application/json'); @@ -196,6 +217,7 @@ module.exports = { assignRole, assignPermission, changePassword, + checkPermission, create, deletePermission, effectivePermissions, diff --git a/test/checkPermission.spec.js b/test/checkPermission.spec.js new file mode 100644 index 0000000..a339bac --- /dev/null +++ b/test/checkPermission.spec.js @@ -0,0 +1,89 @@ +/* eslint-env jest */ + +const { user, Connection } = require('../lib'); +const { + seedDatabase, + dropDatabase, + generateDatabaseName, + generateRandomString, + ConnectionFactory, +} = require('./setup-database'); + +// TODO skipped until Stardog v12 is released +describe.skip('checkPermission()', () => { + const database = generateDatabaseName(); + let conn; + + beforeAll(seedDatabase(database)); + afterAll(dropDatabase(database)); + + beforeEach(() => { + conn = ConnectionFactory(); + }); + + it('should return true for a permission the admin user has', () => + user.checkPermission(conn, 'READ', 'db', database).then(res => { + expect(res.status).toBe(200); + expect(res.body.hasPermission).toBe(true); + })); + + it('should return false for a permission a new user does not have', () => { + const username = generateRandomString(); + const password = generateRandomString(); + + return user + .create(conn, { username, password }) + .then(res => { + expect(res.status).toBe(201); + // Create a new connection for the unprivileged user + const userConn = new Connection({ + username, + password, + endpoint: conn.uri(), + }); + return user.checkPermission(userConn, 'WRITE', 'db', database); + }) + .then(res => { + expect(res.status).toBe(200); + expect(res.body.hasPermission).toBe(false); + }); + }); + + it('should return true after assigning a permission to a user', () => { + const username = generateRandomString(); + const password = generateRandomString(); + const userConn = new Connection({ + username, + password, + endpoint: conn.uri(), + }); + const permission = { + action: 'WRITE', + resourceType: 'db', + resources: [database], + }; + + return user + .create(conn, { username, password }) + .then(res => { + expect(res.status).toBe(201); + // First verify the user does not have the permission + return user.checkPermission(userConn, 'WRITE', 'db', database); + }) + .then(res => { + expect(res.status).toBe(200); + expect(res.body.hasPermission).toBe(false); + // Now assign the permission + return user.assignPermission(conn, username, permission); + }) + .then(res => { + expect(res.status).toBe(201); + // Verify the user now has the permission + return user.checkPermission(userConn, 'WRITE', 'db', database); + }) + .then(res => { + expect(res.status).toBe(200); + expect(res.body.hasPermission).toBe(true); + }); + }); +});