Skip to content

Commit

Permalink
Merge pull request #513 from openannotation/authz-ident-extensions
Browse files Browse the repository at this point in the history
Authz ident extensions
  • Loading branch information
nickstenning committed Apr 25, 2015
2 parents c601e9b + eb55f3d commit 70793fd
Show file tree
Hide file tree
Showing 5 changed files with 152 additions and 91 deletions.
8 changes: 3 additions & 5 deletions src/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,12 @@ function App() {
this._started = false;

// Register a bunch of default utilities
this.registry.registerUtility(authz.defaultAuthorizationPolicy,
'authorizationPolicy');
this.registry.registerUtility(identity.defaultIdentityPolicy,
'identityPolicy');
this.registry.registerUtility(notification.defaultNotifier,
'notifier');

// And set up a default storage component.
// And set up default components.
this.include(authz.acl);
this.include(identity.simple);
this.include(storage.noop);
}

Expand Down
153 changes: 91 additions & 62 deletions src/authz.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,74 +2,103 @@

"use strict";

var AclAuthzPolicy;


/**
* data:: defaultAuthorizationPolicy
* function:: acl()
*
* A module that configures and registers an instance of
* :class:`annotator.identity.AclAuthzPolicy`.
*
* Default authorization policy.
*/
exports.defaultAuthorizationPolicy = {
/**
* function:: defaultAuthorizationPolicy.permits(action,
* annotation,
* identity)
*
* Determines whether the user identified by `identity` is permitted to
* perform the specified action on the given annotation.
*
* If the annotation has a "permissions" object property, then actions will
* be permitted if either of the following are true:
*
* a) annotation.permissions[action] is undefined or null,
* b) annotation.permissions[action] is an Array containing `identity`.
*
* If the annotation has a "user" property, then actions will be permitted
* only if `identity` matches this "user" property.
*
* If the annotation has neither a "permissions" property nor a "user"
* property, then all actions will be permitted.
*
* :param String action: The action the user wishes to perform.
* :param annotation:
* :param identity: The identity of the user.
*
* :returns Boolean: Whether the action is permitted.
*/
permits: function permits(action, annotation, identity) {
var userid = this.authorizedUserId(identity);

if (annotation.permissions) {
// Fine-grained authorization on permissions field
var tokens = annotation.permissions[action];

if (typeof tokens === 'undefined' || tokens === null) {
// Missing tokens array for this action: anyone can perform
// action.
return true;
}
exports.acl = function acl() {
var authorization = new AclAuthzPolicy();

for (var i = 0, len = tokens.length; i < len; i++) {
if (userid === tokens[i]) {
return true;
}
}
return {
configure: function (registry) {
registry.registerUtility(authorization, 'authorizationPolicy');
}
};
};


/**
* class:: AclAuthzPolicy()
*
* An authorization policy that permits actions based on access control lists.
*
*/
AclAuthzPolicy = exports.AclAuthzPolicy = function AclAuthzPolicy() {
};

// No tokens matched: action should not be performed.
return false;
} else if (annotation.user) {
// Coarse-grained authorization
return userid === annotation.user;

/**
* function:: AclAuthzPolicy.prototype.permits(action, context, identity)
*
* Determines whether the user identified by `identity` is permitted to
* perform the specified action in the given context.
*
* If the context has a "permissions" object property, then actions will
* be permitted if either of the following are true:
*
* a) permissions[action] is undefined or null,
* b) permissions[action] is an Array containing the authorized userid
* for the given identity.
*
* If the context has no permissions associated with it then all actions
* will be permitted.
*
* If the annotation has a "user" property, then actions will be permitted
* only if `identity` matches this "user" property.
*
* If the annotation has neither a "permissions" property nor a "user"
* property, then all actions will be permitted.
*
* :param String action: The action to perform.
* :param context: The permissions context for the authorization check.
* :param identity: The identity whose authorization is being checked.
*
* :returns Boolean: Whether the action is permitted in this context for this
* identity.
*/
AclAuthzPolicy.prototype.permits = function (action, context, identity) {
var userid = this.authorizedUserId(identity);
var permissions = context.permissions;

if (permissions) {
// Fine-grained authorization on permissions field
var tokens = permissions[action];

if (typeof tokens === 'undefined' || tokens === null) {
// Missing tokens array for this action: anyone can perform
// action.
return true;
}

// No authorization info on annotation: free-for-all!
return true;
},

/**
* function:: defaultAuthorizationPolicy.authorizedUserId(identity)
*
* Returns the authorized userid for the user identified by `identity`.
*/
authorizedUserId: function authorizedUserId(identity) {
return identity;
for (var i = 0, len = tokens.length; i < len; i++) {
if (userid === tokens[i]) {
return true;
}
}

// No tokens matched: action should not be performed.
return false;
} else if (context.user) {
// Coarse-grained authorization
return userid === context.user;
}

// No authorization info on context: free-for-all!
return true;
};


/**
* function:: AclAuthzPolicy.prototype.authorizedUserId(identity)
*
* Returns the authorized userid for the user identified by `identity`.
*/
AclAuthzPolicy.prototype.authorizedUserId = function (identity) {
return identity;
};
46 changes: 35 additions & 11 deletions src/identity.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,34 @@
"use strict";


var SimpleIdentityPolicy;


/**
* function:: simple()
* A module that configures and registers an instance of
* :class:`annotator.identity.SimpleIdentityPolicy`.
*/
exports.simple = function simple() {
var identity = new SimpleIdentityPolicy();

return {
configure: function (registry) {
registry.registerUtility(identity, 'identityPolicy');
}
};
};


/**
* data:: defaultIdentityPolicy
* class:: SimpleIdentityPolicy
*
* Default identity policy.
* A simple identity policy that considers the identity to be an opaque
* identifier.
*/
exports.defaultIdentityPolicy = {
SimpleIdentityPolicy = function SimpleIdentityPolicy() {
/**
* data:: defaultIdentityPolicy.identity
* data:: SimpleIdentityPolicy.identity
*
* Default identity. Defaults to `null`, which disables identity-related
* functionality.
Expand All @@ -20,12 +40,16 @@ exports.defaultIdentityPolicy = {
*
* app.ident.identity = 'bob';
*/
identity: null,
this.identity = null;
};
exports.SimpleIdentityPolicy = SimpleIdentityPolicy;

/**
* function:: defaultIdentityPolicy.who()
*
* Returns the current user identity.
*/
who: function () { return this.identity; }

/**
* function:: SimpleIdentityPolicy.prototype.who()
*
* Returns the current user identity.
*/
SimpleIdentityPolicy.prototype.who = function () {
return this.identity;
};
22 changes: 13 additions & 9 deletions test/spec/authz_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,40 +3,44 @@ var assert = require('assertive-chai').assert;
var authz = require('../../src/authz');


describe('authz.defaultAuthorizationPolicy', function () {
var p = authz.defaultAuthorizationPolicy;
describe('authz.AclAuthzPolicy', function () {
var p;

beforeEach(function () {
p = new authz.AclAuthzPolicy();
});

describe('.permits(...)', function () {
it('permits any action for an annotation with no authorisation info', function () {
it('permits any action if there is no permission info', function () {
assert.isTrue(p.permits('foo', {}, null));
assert.isTrue(p.permits('foo', {}, 'alice'));
});

it('refuses any action if an annotation has a user and no identity is set', function () {
it('refuses any action if an context has a user and no identity is set', function () {
assert.isFalse(p.permits('foo', {user: 'alice'}, null));
});

it('permits any action if annotation has a user which matches the identity', function () {
it('permits any action if context has a user which matches the identity', function () {
assert.isTrue(p.permits('foo', {user: 'alice'}, 'alice'));
});

it('refuses any action if annotation has a user which does not match the identity', function () {
it('refuses any action if context has a user which does not match the identity', function () {
assert.isFalse(p.permits('foo', {user: 'alice'}, 'bob'));
});

it('permits any action if annotation.permissions[action] is undefined or null', function () {
it('permits any action if permissions are undefined or null', function () {
var a = {permissions: {}};
assert.isTrue(p.permits('foo', a, null));
assert.isTrue(p.permits('foo', a, 'alice'));
});

it('refuses an action if annotation.permissions[action] == []', function () {
it('refuses an action if permissions[action] == []', function () {
var a = {permissions: {'foo': []}};
assert.isFalse(p.permits('foo', a, null));
assert.isFalse(p.permits('foo', a, 'bob'));
});

it('permits an action if annotation.permissions[action] contains >0 tokens which match the identity', function () {
it('permits an action if permissions[action] contains >0 tokens which match the identity', function () {
var a = {permissions: {'foo': ['alice']}};
assert.isTrue(p.permits('foo', a, 'alice'));
});
Expand Down
14 changes: 10 additions & 4 deletions test/spec/identity_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,21 @@ var assert = require('assertive-chai').assert;
var identity = require('../../src/identity');


describe('identity.defaultIdentityPolicy', function () {
describe('identity.SimpleIdentityPolicy', function () {
var ident;

beforeEach(function () {
ident = new identity.SimpleIdentityPolicy();
});

describe('.who()', function () {
it('returns null', function () {
assert.isNull(identity.defaultIdentityPolicy.who());
assert.isNull(ident.who());
});

it('returns .identity if set', function () {
identity.defaultIdentityPolicy.identity = 'alice';
assert.equal('alice', identity.defaultIdentityPolicy.who());
ident.identity = 'alice';
assert.equal('alice', ident.who());
});
});
});

0 comments on commit 70793fd

Please sign in to comment.