add dataset & scopes to token (#20)

This commit is contained in:
ranbreuer 2017-01-09 12:10:49 +02:00 коммит произвёл GitHub
Родитель 854451d8a5
Коммит 1b2eec94a9
4 изменённых файлов: 151 добавлений и 10 удалений

Просмотреть файл

@ -43,7 +43,7 @@ Each API call sets the following HTTP header:
## Creating Embed Tokens
Power BI Embedded uses embed token, which are HMAC signed JSON Web Tokens. The tokens are signed with the access key from your Azure Power BI Embedded workspace collection.
Embed tokens are used to provide read only access to a report to embed into an application.
Embed tokens, by default, are used to provide read only access to a report to embed into an application.
### Required Claims
- ver: 0.2.0
@ -87,3 +87,45 @@ The following decoded JSON web token
"nbf": 1360043456
}
```
## Adding Permission Scopes to Embed Tokens
When using Embed tokens, one might want to restrict usage of the resources he gives access to. For this reason, you can generate a token with scoped permissions.
### Required Claims - Scopes
- scp: {scopesClaim}
scopesClaim can be either a string or array of strings, noting the allowed permissions to workspace resources (Report, Dataset, etc.)
```javascript
var powerbi = require('powerbi-api');
var reportReadScope = 'Report.Read';
var token = powerbi.PowerBIToken.createReportEmbedToken('{WorkspaceCollection}', '{workspaceId}', '{reportId}', '{scopes}');
var jwt = token.generate('{AccessKey}');
```
## Token Example - With Scopes
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ2ZXIiOiIwLjIuMCIsIndjbiI6IlN1cHBvcnREZW1vIiwid2lkIjoiY2E2NzViMTktNmMzYy00MDAzLTg4MDgtMWM3ZGRjNmJkODA5IiwicmlkIjoiOTYyNDFmMGYtYWJhZS00ZWE5LWEwNjUtOTNiNDI4ZWRkYjE3Iiwic2NwIjoiUmVwb3J0LlJlYWQiLCJpc3MiOiJQb3dlckJJU0RLIiwiYXVkIjoiaHR0cHM6Ly9hbmFseXNpcy53aW5kb3dzLm5ldC9wb3dlcmJpL2FwaSIsImV4cCI6MTM2MDA0NzA1NiwibmJmIjoxMzYwMDQzNDU2fQ.M1jkWXnkfwJeGQqh1x0vIAYB4EBKbHSZFoDB6n_LZyA
### Decoded
The following decoded JSON web token
**Header**
```javascript
{
"typ": "JWT",
"alg": "HS256"
}
```
**Payload**
```javascript
{
"ver": "0.2.0",
"wcn": "SupportDemo",
"wid": "ca675b19-6c3c-4003-8808-1c7ddc6bd809",
"rid": "96241f0f-abae-4ea9-a065-93b428eddb17",
"scp": "Report.Read",
"iss": "PowerBISDK",
"aud": "https://analysis.windows.net/powerbi/api",
"exp": 1360047056,
"nbf": 1360043456
}

Просмотреть файл

@ -14,18 +14,28 @@ export class PowerBIToken {
};
}
public static createReportEmbedToken(workspaceCollectionName: string, workspaceId: string, reportId: string, username: string = null, roles: string|string[] = null, expiration: Date = null): PowerBIToken {
public static createReportEmbedToken(workspaceCollectionName: string, workspaceId: string, reportId?: string, datasetId?: string, scopes: string|string[] = '', username: string = null, roles: string|string[] = null, expiration: Date = null): PowerBIToken {
if (roles && !username)
{
if (roles && !username) {
throw new Error('Cannot have an empty or null Username claim with the non-empty Roles claim');
}
if (!reportId && !datasetId) {
throw new Error('Token must contain either reportId or datasetId claim');
}
var token = new PowerBIToken(expiration);
token.addClaim('wcn', workspaceCollectionName);
token.addClaim('wid', workspaceId);
token.addClaim('rid', reportId);
if (reportId) {
token.addClaim('rid', reportId);
}
if (datasetId) {
token.addClaim('did', datasetId);
}
if(username != null) {
token.addClaim('username', username);
@ -34,6 +44,14 @@ export class PowerBIToken {
}
}
if (scopes) {
if (Array.isArray(scopes)) {
scopes = (<string[]>scopes).join(' ');
}
token.addClaim('scp', scopes);
}
return token;
}

Просмотреть файл

@ -1,6 +1,6 @@
{
"name": "powerbi-api",
"version": "1.0.1",
"version": "1.0.2",
"description": "Node client library for Power BI API",
"main": "./lib/index.js",
"typings": "./lib/index.d.ts",

Просмотреть файл

@ -11,8 +11,12 @@ describe('Power BI Token', () => {
const workspacCollection: string = 'TestCollection';
const workspaceId: string = 'fd41b1db-9e26-4103-99a7-f9ad336b99a7';
const reportId: string = 'fe607ad3-97bf-4dd5-98eb-db4a4d5de4e0';
const datasetId: string = 'fe123ad3-97bf-4dd5-98eb-db7c432de4e0';
const accessKey: string = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890';
const username: string = 'TestUser';
const scopes: string = 'Scope1';
const scopesArray: string[] = ['Scope1', 'Scope2'];
const scopesArrayDecoded: string = 'Scope1 Scope2';
it('is defined', () => {
expect(powerbi.PowerBIToken).to.exist;
@ -66,6 +70,13 @@ describe('Power BI Token', () => {
expect(jwt).not.to.be.null;
});
it('can be created for datasetId', () => {
let token = powerbi.PowerBIToken.createReportEmbedToken(workspacCollection, workspaceId, null, datasetId);
let jwt = token.generate(accessKey);
expect(jwt).not.to.be.null;
});
it('are created with a default expiration', () => {
let nbf = powerbi.Util.getUnixTime(new Date());
let exp = nbf + 3600;
@ -78,12 +89,75 @@ describe('Power BI Token', () => {
expect(decoded.exp).to.equal(exp)
});
it('are created with the correct claims - minimal params', () => {
let nbf = powerbi.Util.getUnixTime(new Date());
let exp = nbf + 3600;
let expiration = new Date(exp * 1000);
let embedToken = powerbi.PowerBIToken.createReportEmbedToken(workspacCollection, workspaceId, reportId);
let token = embedToken.generate(accessKey);
let decoded = jwt.decode(token, accessKey);
expect(decoded.ver).to.equal(version);
expect(decoded.aud).to.equal(resource);
expect(decoded.iss).to.equal(issuer);
expect(decoded.wcn).to.equal(workspacCollection);
expect(decoded.wid).to.equal(workspaceId);
expect(decoded.rid).to.equal(reportId);
});
it('are created with the correct claims', () => {
let nbf = powerbi.Util.getUnixTime(new Date());
let exp = nbf + 3600;
let expiration = new Date(exp * 1000);
let embedToken = powerbi.PowerBIToken.createReportEmbedToken(workspacCollection, workspaceId, reportId, username, 'TestRole', expiration);
let embedToken = powerbi.PowerBIToken.createReportEmbedToken(workspacCollection, workspaceId, reportId, datasetId, scopes, username, 'TestRole', expiration);
let token = embedToken.generate(accessKey);
let decoded = jwt.decode(token, accessKey);
expect(decoded.ver).to.equal(version);
expect(decoded.aud).to.equal(resource);
expect(decoded.iss).to.equal(issuer);
expect(decoded.wcn).to.equal(workspacCollection);
expect(decoded.wid).to.equal(workspaceId);
expect(decoded.rid).to.equal(reportId);
expect(decoded.did).to.equal(datasetId);
expect(decoded.nbf).to.equal(nbf);
expect(decoded.exp).to.equal(exp);
expect(decoded.scp).to.equal(scopes);
expect(decoded.username).to.equal(username);
expect(decoded.roles).to.equal('TestRole');
});
it('are created with the correct claims - datasetId only', () => {
let nbf = powerbi.Util.getUnixTime(new Date());
let exp = nbf + 3600;
let expiration = new Date(exp * 1000);
let embedToken = powerbi.PowerBIToken.createReportEmbedToken(workspacCollection, workspaceId, null, datasetId, scopes, username, 'TestRole', expiration);
let token = embedToken.generate(accessKey);
let decoded = jwt.decode(token, accessKey);
expect(decoded.ver).to.equal(version);
expect(decoded.aud).to.equal(resource);
expect(decoded.iss).to.equal(issuer);
expect(decoded.wcn).to.equal(workspacCollection);
expect(decoded.wid).to.equal(workspaceId);
expect(decoded.rid).to.be.undefined;
expect(decoded.did).to.equal(datasetId);
expect(decoded.nbf).to.equal(nbf);
expect(decoded.exp).to.equal(exp);
expect(decoded.scp).to.equal(scopes);
expect(decoded.username).to.equal(username);
expect(decoded.roles).to.equal('TestRole');
});
it('are created with the correct claims - scopes as array', () => {
let nbf = powerbi.Util.getUnixTime(new Date());
let exp = nbf + 3600;
let expiration = new Date(exp * 1000);
let embedToken = powerbi.PowerBIToken.createReportEmbedToken(workspacCollection, workspaceId, reportId, null, scopesArray, username, 'TestRole', expiration);
let token = embedToken.generate(accessKey);
let decoded = jwt.decode(token, accessKey);
@ -95,17 +169,18 @@ describe('Power BI Token', () => {
expect(decoded.rid).to.equal(reportId);
expect(decoded.nbf).to.equal(nbf);
expect(decoded.exp).to.equal(exp);
expect(decoded.scp).to.equal(scopesArrayDecoded);
expect(decoded.username).to.equal(username);
expect(decoded.roles).to.equal('TestRole');
});
it('are created with multiple RLS roles', () => {
let nbf = powerbi.Util.getUnixTime(new Date());
let exp = nbf + 3600;
let expiration = new Date(exp * 1000);
let roles = ['TestRole1', 'TestRole2'];
let embedToken = powerbi.PowerBIToken.createReportEmbedToken(workspacCollection, workspaceId, reportId, username, roles, expiration);
let embedToken = powerbi.PowerBIToken.createReportEmbedToken(workspacCollection, workspaceId, reportId, datasetId, scopes, username, roles, expiration);
let token = embedToken.generate(accessKey);
let decoded = jwt.decode(token, accessKey);
@ -113,6 +188,12 @@ describe('Power BI Token', () => {
expect(decoded.roles).to.eql(roles);
});
it('fail to create when missing reportId and datasetId', () => {
expect(powerbi.PowerBIToken.createReportEmbedToken.bind(powerbi.PowerBIToken, workspacCollection, workspaceId))
.to
.throw('Token must contain either reportId or datasetId claim');
});
it('fail to create when RLS username is empty and roles is not', () => {
let nbf = powerbi.Util.getUnixTime(new Date());
let exp = nbf + 3600;
@ -121,7 +202,7 @@ describe('Power BI Token', () => {
let badUsernames = [null, undefined, ''];
badUsernames.forEach(badUsername => {
expect(powerbi.PowerBIToken.createReportEmbedToken.bind(powerbi.PowerBIToken, workspacCollection, workspaceId, reportId, badUsername, role, expiration))
expect(powerbi.PowerBIToken.createReportEmbedToken.bind(powerbi.PowerBIToken, workspacCollection, workspaceId, reportId, datasetId, scopes, badUsername, role, expiration))
.to
.throw('Cannot have an empty or null Username claim with the non-empty Roles claim');
}