Skip to content

Commit

Permalink
Allow ACL wildcards at root level (contributes to #670) (hyperledger-…
Browse files Browse the repository at this point in the history
  • Loading branch information
Simon Stone authored Oct 2, 2017
1 parent 5b5778a commit 25a3330
Show file tree
Hide file tree
Showing 6 changed files with 55 additions and 6 deletions.
5 changes: 5 additions & 0 deletions packages/composer-common/lib/acl/modelbinding.js
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,11 @@ class ModelBinding {
if (ModelUtil.isRecursiveWildcardName(this.qualifiedName)) {
const namespaces = mm.getNamespaces();

// Check for recursive glob only
if (!ns) {
return;
}

if (namespaces.findIndex(function (element, index, array) {
return (ns === element || element.startsWith(ns + '.'));
})=== -1) {
Expand Down
23 changes: 18 additions & 5 deletions packages/composer-common/lib/acl/parser.pegjs
Original file line number Diff line number Diff line change
Expand Up @@ -1449,12 +1449,20 @@ BindingNoInstance
};
}

BindingRootRecursive
= '**'
{
return {
type: "BindingRootRecursive",
qualifiedName: '**',
location: location()
};
}

Noun
= Binding
/ BindingNoInstance

NounNoInstance
= BindingNoInstance
/ BindingRootRecursive

/**
* A single verb.
Expand Down Expand Up @@ -1494,6 +1502,7 @@ Participant
= 'ANY'
/ Binding
/ BindingNoInstance
/ BindingRootRecursive

Predicate
= "(" __ test:$Expression __ ")" __
Expand All @@ -1509,16 +1518,20 @@ StringSequence "string"
return chars.join("");
}

Transaction
= BindingNoInstance
/ BindingRootRecursive

SimpleTransactionSpecification
= "transaction:" __ "\"" binding:BindingNoInstance "\"" __
= "transaction:" __ "\"" binding:Transaction "\"" __
{
return {
binding: binding
};
}

ConditionalTransactionSpecification
= "transaction" __ variableBinding:VariableBinding? __ ":" __ "\"" binding:BindingNoInstance "\"" __
= "transaction" __ variableBinding:VariableBinding? __ ":" __ "\"" binding:Transaction "\"" __
{
return {
variableBinding: variableBinding,
Expand Down
2 changes: 2 additions & 0 deletions packages/composer-common/lib/modelutil.js
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,8 @@ class ModelUtil {
// matching namespace
} else if (ModelUtil.isRecursiveWildcardName(fqn) && (typeNS + '.').startsWith(ns + '.')) {
// matching recursive namespace
} else if (ModelUtil.isRecursiveWildcardName(fqn) && !ns) {
// matching root recursive namespace
} else {
// does not match
return false;
Expand Down
7 changes: 7 additions & 0 deletions packages/composer-common/test/acl/modelbinding.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ describe('ModelBinding', () => {
const classAst = {'type':'Binding','qualifiedName':'org.acme.Car'};
const classWithIdentifierAst = {'type':'Binding','qualifiedName':'org.acme.Car','instanceId':'ABC123'};
const variableAst = {'type':'Identifier','name':'dan'};
const rootRecursiveNamespaceAst = {'type':'BindingRootRecursive','qualifiedName':'**'};

const missingClass = {'type':'Binding','qualifiedName':'org.acme.Missing','instanceId':'ABC123'};
const missingNamespace = {'type':'Binding','qualifiedName':'org.missing.Missing.*'};
Expand Down Expand Up @@ -94,6 +95,12 @@ describe('ModelBinding', () => {
modelBinding.toString().should.equal('ModelBinding org.acme.Car');
});

it('should validate correct contents for a root recursive namespace reference', () => {
modelBinding = new ModelBinding( aclRule, rootRecursiveNamespaceAst );
modelBinding.validate();
modelBinding.toString().should.equal('ModelBinding **');
});

it('should validate correct contents for a class reference with an identifier', () => {
modelBinding = new ModelBinding( aclRule, classWithIdentifierAst );
modelBinding.validate();
Expand Down
4 changes: 4 additions & 0 deletions packages/composer-common/test/modelutil.js
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,10 @@ describe('ModelUtil', function () {
it('should return false for a non-matching recursive wildcard', () => {
ModelUtil.isMatchingType(type, 'org.ac.**').should.be.false;
});

it('should return true for a root recursive wildcard match', () => {
ModelUtil.isMatchingType(type, '**').should.be.true;
});
});

describe('#getNamespace', function() {
Expand Down
20 changes: 19 additions & 1 deletion packages/composer-runtime/test/accesscontroller.js
Original file line number Diff line number Diff line change
Expand Up @@ -377,6 +377,12 @@ describe('AccessController', () => {
.should.be.true;
});

it('should return true if the ACL rule specifies a matching root recursive namespace', () => {
setAclFile('rule R1 {description: "Test R1" participant: "org.acme.test.TestParticipant#P5678" operation: READ resource: "**" action: ALLOW}');
controller.matchNoun(asset, aclManager.getAclRules()[0])
.should.be.true;
});

it('should return false if the ACL rule specifies a non-matching fully qualified identifier', () => {
setAclFile('rule R1 {description: "Test R1" participant: "org.acme.test.TestParticipant#P5678" operation: READ resource: "org.acme.test.TestAsset#A5678" action: ALLOW}');
controller.matchNoun(asset, aclManager.getAclRules()[0])
Expand Down Expand Up @@ -482,6 +488,12 @@ describe('AccessController', () => {
.should.be.true;
});

it('should return true if the ACL rule specifies a matching root recursive namespace', () => {
setAclFile('rule R1 {description: "Test R1" participant: "**" operation: READ resource: "org.acme.test.TestAsset#A1234" action: ALLOW}');
controller.matchParticipant(participant, aclManager.getAclRules()[0])
.should.be.true;
});

it('should return false if the ACL rule specifies a non-matching fully qualified identifier', () => {
setAclFile('rule R1 {description: "Test R1" participant: "org.acme.test.TestParticipant#P1234" operation: READ resource: "org.acme.test.TestAsset#A1234" action: ALLOW}');
controller.matchParticipant(participant, aclManager.getAclRules()[0])
Expand Down Expand Up @@ -556,12 +568,18 @@ describe('AccessController', () => {
.should.be.true;
});

it('should return true if the ACL rule specifies a matching recusive namespace', () => {
it('should return true if the ACL rule specifies a matching recursive namespace', () => {
setAclFile('rule R1 {description: "Test R1" participant: "ANY" operation: READ resource: "org.acme.test.TestAsset#A1234" transaction: "org.acme.test.**" action: ALLOW}');
controller.matchTransaction(transaction, aclManager.getAclRules()[0])
.should.be.true;
});

it('should return true if the ACL rule specifies a matching root recursive namespace', () => {
setAclFile('rule R1 {description: "Test R1" participant: "ANY" operation: READ resource: "org.acme.test.TestAsset#A1234" transaction: "**" action: ALLOW}');
controller.matchTransaction(transaction, aclManager.getAclRules()[0])
.should.be.true;
});

it('should return false if the ACL rule specifies a non-matching fully qualified name', () => {
setAclFile('rule R1 {description: "Test R1" participant: "ANY" operation: READ resource: "org.acme.test.TestAsset#A1234" transaction: "org.acme.test.TestTransaction2" action: ALLOW}');
controller.matchTransaction(transaction, aclManager.getAclRules()[0])
Expand Down

0 comments on commit 25a3330

Please sign in to comment.