feat: RBAC authentication contract and role library

This commit is contained in:
Matt Condon
2017-11-24 12:56:03 +02:00
parent dd1fd0002a
commit e931c1cbfc
5 changed files with 362 additions and 0 deletions

77
test/RBAC.js Normal file
View File

@ -0,0 +1,77 @@
const RBACMock = artifacts.require('./helpers/RBACMock.sol')
import expectThrow from './helpers/expectThrow'
require('chai')
.use(require('chai-as-promised'))
.should()
contract('RBAC', function(accounts) {
let mock
const [
owner,
anyone,
...advisors
] = accounts
before(async () => {
mock = await RBACMock.new(advisors, { from: owner })
})
context('in normal conditions', () => {
it('allows owner to call #onlyOwnersCanDoThis', async () => {
await mock.onlyOwnersCanDoThis({ from: owner })
.should.be.fulfilled
})
it('allows owner to call #onlyAdvisorsCanDoThis', async () => {
await mock.onlyAdvisorsCanDoThis({ from: owner })
.should.be.fulfilled
})
it('allows advisors to call #onlyAdvisorsCanDoThis', async () => {
await mock.onlyAdvisorsCanDoThis({ from: advisors[0] })
.should.be.fulfilled
})
it('allows owner to call #eitherOwnerOrAdvisorCanDoThis', async () => {
await mock.eitherOwnerOrAdvisorCanDoThis({ from: owner })
.should.be.fulfilled
})
it('allows advisors to call #eitherOwnerOrAdvisorCanDoThis', async () => {
await mock.eitherOwnerOrAdvisorCanDoThis({ from: advisors[0] })
.should.be.fulfilled
})
it('does not allow owners to call #nobodyCanDoThis', async () => {
expectThrow(
mock.nobodyCanDoThis({ from: owner })
)
})
it('does not allow advisors to call #nobodyCanDoThis', async () => {
expectThrow(
mock.nobodyCanDoThis({ from: advisors[0] })
)
})
it('does not allow anyone to call #nobodyCanDoThis', async () => {
expectThrow(
mock.nobodyCanDoThis({ from: anyone })
)
})
it('allows an owner to remove an advisor\'s role', async () => {
await mock.removeAdvisor(advisors[0], { from: owner })
.should.be.fulfilled
})
})
context('in adversarial conditions', () => {
it('does not allow an advisor to remove another advisor', async () => {
expectThrow(
mock.removeAdvisor(advisors[1], { from: advisors[0] })
)
})
it('does not allow "anyone" to remove an advisor', async () => {
expectThrow(
mock.removeAdvisor(advisors[0], { from: anyone })
)
})
})
})

68
test/helpers/RBACMock.sol Normal file
View File

@ -0,0 +1,68 @@
pragma solidity ^0.4.8;
import '../../contracts/ownership/rbac/RBAC.sol';
contract RBACMock is RBAC {
modifier onlyOwnerOrAdvisor()
{
require(
hasRole(msg.sender, "owner") ||
hasRole(msg.sender, "advisor")
);
_;
}
function RBACMock(address[] _advisors)
public
{
addRole(msg.sender, "owner");
addRole(msg.sender, "advisor");
for (uint256 i = 0; i < _advisors.length; i++) {
addRole(_advisors[i], "advisor");
}
}
function onlyOwnersCanDoThis()
onlyRole("owner")
view
external
{
}
function onlyAdvisorsCanDoThis()
onlyRole("advisor")
view
external
{
}
function eitherOwnerOrAdvisorCanDoThis()
onlyOwnerOrAdvisor
view
external
{
}
function nobodyCanDoThis()
onlyRole("unknown")
view
external
{
}
// owners can remove advisor's role
function removeAdvisor(address _addr)
onlyRole("owner")
public
{
// revert if the user isn't an advisor
// (perhaps you want to soft-fail here instead?)
checkRole(_addr, "advisor");
// remove the advisor's role
removeRole(_addr, "advisor");
}
}