This commit is contained in:
thosakwe 2017-01-29 15:21:52 -05:00
parent a4fa416dfe
commit 315709e39a
8 changed files with 87 additions and 26 deletions

View file

@ -1,5 +1,5 @@
# security # security
[![version 0.0.5](https://img.shields.io/badge/pub-v0.0.5-red.svg)](https://pub.dartlang.org/packages/angel_security) [![version 0.0.6](https://img.shields.io/badge/pub-v0.0.6-red.svg)](https://pub.dartlang.org/packages/angel_security)
[![build status](https://travis-ci.org/angel-dart/security.svg)](https://travis-ci.org/angel-dart/security) [![build status](https://travis-ci.org/angel-dart/security.svg)](https://travis-ci.org/angel-dart/security)
Angel middleware designed to enhance application security by patching common Web security Angel middleware designed to enhance application security by patching common Web security

View file

@ -1,20 +1,23 @@
import 'dart:mirrors';
import 'package:angel_framework/angel_framework.dart'; import 'package:angel_framework/angel_framework.dart';
import 'errors.dart'; import 'errors.dart';
import 'is_server_side.dart'; import 'is_server_side.dart';
/// Adds the authed user's id to `data`. /// Adds the authed user's id to `data`.
/// ///
/// Default [as] is `'userId'`. ///Default [idField] is `'id'`.
/// Default [ownerField] is `'userId'`.
/// Default [userKey] is `'user'`. /// Default [userKey] is `'user'`.
HookedServiceEventListener associateCurrentUser( HookedServiceEventListener associateCurrentUser(
{String as, {String idField,
String ownerField,
String userKey, String userKey,
String errorMessage, String errorMessage,
bool allowNullUserId: false, bool allowNullUserId: false,
getId(user), getId(user),
setId(id, user)}) { assignUserId(id, obj)}) {
return (HookedServiceEvent e) async { return (HookedServiceEvent e) async {
var fieldName = as?.isNotEmpty == true ? as : 'userId'; var fieldName = ownerField?.isNotEmpty == true ? ownerField : 'userId';
var user = e.request?.grab(userKey ?? 'user'); var user = e.request?.grab(userKey ?? 'user');
if (user == null) { if (user == null) {
@ -25,7 +28,18 @@ HookedServiceEventListener associateCurrentUser(
return; return;
} }
_getId(user) => getId == null ? user?.id : getId(user); _getId(user) {
if (getId != null)
return getId(user);
else if (user is Map)
return user[idField ?? 'id'];
else if (user is Extensible)
return user.properties[idField ?? 'id'];
else if (idField == null || idField == 'id')
return user.id;
else
return reflect(user).getField(new Symbol(idField ?? 'id')).reflectee;
}
var id = await _getId(user); var id = await _getId(user);
@ -33,15 +47,19 @@ HookedServiceEventListener associateCurrentUser(
throw new AngelHttpException.notProcessable( throw new AngelHttpException.notProcessable(
message: 'Current user is missing a $fieldName field.'); message: 'Current user is missing a $fieldName field.');
_setId(id, user) { _assignUserId(id, obj) {
if (setId != null) if (assignUserId != null)
return setId(id, user); return assignUserId(id, obj);
else if (user is Map) else if (obj is Map)
user[fieldName] = id; obj[fieldName] = id;
else if (obj is Extensible)
obj.properties[fieldName] = id;
else if (fieldName == 'userId')
obj.userId = id;
else else
user.userId = id; reflect(obj).setField(new Symbol(fieldName), id);
} }
await _setId(id, e.data); await _assignUserId(id, e.data);
}; };
} }

View file

@ -1,4 +1,5 @@
import 'dart:async'; import 'dart:async';
import 'dart:mirrors';
import 'package:crypto/crypto.dart'; import 'package:crypto/crypto.dart';
import 'package:angel_framework/angel_framework.dart'; import 'package:angel_framework/angel_framework.dart';
@ -19,8 +20,12 @@ HookedServiceEventListener hashPassword(
return getPassword(user); return getPassword(user);
else if (user is Map) else if (user is Map)
return user[passwordField ?? 'password']; return user[passwordField ?? 'password'];
else else if (user is Extensible)
return user.properties[passwordField ?? 'password'];
else if (passwordField == 'password')
return user?.password; return user?.password;
else
return reflect(user).getField(new Symbol(passwordField ?? 'password')).reflectee;
} }
_setPassword(password, user) { _setPassword(password, user) {
@ -28,8 +33,11 @@ HookedServiceEventListener hashPassword(
return setPassword(password, user); return setPassword(password, user);
else if (user is Map) else if (user is Map)
user[passwordField ?? 'password'] = password; user[passwordField ?? 'password'] = password;
else if (user is Extensible)
user.properties[passwordField ?? password] = password;
else else
user?.password = password; reflect(user)
.setField(new Symbol(passwordField ?? 'password'), password);
} }
if (e.data != null) { if (e.data != null) {

View file

@ -1,3 +1,4 @@
import 'dart:mirrors';
import 'package:angel_framework/angel_framework.dart'; import 'package:angel_framework/angel_framework.dart';
import 'errors.dart'; import 'errors.dart';
import 'is_server_side.dart'; import 'is_server_side.dart';
@ -8,12 +9,13 @@ import 'is_server_side.dart';
/// Default [userKey] is `'user'`. /// Default [userKey] is `'user'`.
HookedServiceEventListener queryWithCurrentUser( HookedServiceEventListener queryWithCurrentUser(
{String as, {String as,
String idField,
String userKey, String userKey,
String errorMessage, String errorMessage,
bool allowNullUserId: false, bool allowNullUserId: false,
getId(user)}) { getId(user)}) {
return (HookedServiceEvent e) async { return (HookedServiceEvent e) async {
var fieldName = as?.isNotEmpty == true ? as : 'userId'; var fieldName = idField?.isNotEmpty == true ? idField : 'id';
var user = e.request?.grab(userKey ?? 'user'); var user = e.request?.grab(userKey ?? 'user');
if (user == null) { if (user == null) {
@ -24,15 +26,26 @@ HookedServiceEventListener queryWithCurrentUser(
return; return;
} }
_getId(user) => getId == null ? user?.id : getId(user); _getId(user) {
if (getId != null)
return getId(user);
else if (user is Map)
return user[fieldName];
else if (user is Extensible)
return user.properties[fieldName];
else if (fieldName == 'id')
return user.id;
else
return reflect(user).getField(new Symbol(fieldName)).reflectee;
}
var id = await _getId(user); var id = await _getId(user);
if (id == null && allowNullUserId != true) if (id == null && allowNullUserId != true)
throw new AngelHttpException.notProcessable( throw new AngelHttpException.notProcessable(
message: 'Current user is missing a $fieldName field.'); message: 'Current user is missing a \'$fieldName\' field.');
var data = {fieldName: id}; var data = {as?.isNotEmpty == true ? as : 'userId': id};
e.params['query'] = e.params.containsKey('query') e.params['query'] = e.params.containsKey('query')
? (e.params['query']..addAll(data)) ? (e.params['query']..addAll(data))

View file

@ -1,10 +1,16 @@
import 'dart:mirrors';
import 'package:angel_framework/angel_framework.dart'; import 'package:angel_framework/angel_framework.dart';
import 'errors.dart'; import 'errors.dart';
import 'is_server_side.dart'; import 'is_server_side.dart';
/// Restricts users to accessing only their own resources. /// Restricts users to accessing only their own resources.
HookedServiceEventListener restrictToOwner( HookedServiceEventListener restrictToOwner(
{String userKey, String errorMessage, getId(user), getOwner(obj)}) { {String idField,
String ownerField,
String userKey,
String errorMessage,
getId(user),
getOwner(obj)}) {
return (HookedServiceEvent e) async { return (HookedServiceEvent e) async {
if (!isServerSide(e)) { if (!isServerSide(e)) {
var user = e.request?.grab(userKey ?? 'user'); var user = e.request?.grab(userKey ?? 'user');
@ -18,9 +24,13 @@ HookedServiceEventListener restrictToOwner(
if (getId != null) if (getId != null)
return getId(user); return getId(user);
else if (user is Map) else if (user is Map)
return user['id']; return user[idField ?? 'id'];
else else if (user is Extensible)
return user.properties[idField ?? 'id'];
else if (idField == null || idField == 'id')
return user.id; return user.id;
else
return reflect(user).getField(new Symbol(idField ?? 'id')).reflectee;
} }
var id = await _getId(user); var id = await _getId(user);
@ -38,9 +48,15 @@ HookedServiceEventListener restrictToOwner(
if (getOwner != null) if (getOwner != null)
return getOwner(obj); return getOwner(obj);
else if (obj is Map) else if (obj is Map)
return obj['userId']; return obj[ownerField ?? 'userId'];
else else if (obj is Extensible)
return obj.properties[ownerField ?? 'userId'];
else if (ownerField == null || ownerField == 'userId')
return obj.userId; return obj.userId;
else
return reflect(obj)
.getField(new Symbol(ownerField ?? 'userId'))
.reflectee;
} }
var ownerId = await _getOwner(resource); var ownerId = await _getOwner(resource);

View file

@ -16,6 +16,8 @@ HookedServiceEventListener variantPermission(
return (HookedServiceEvent e) async { return (HookedServiceEvent e) async {
var permission = await createPermission(e); var permission = await createPermission(e);
if (permission is PermissionBuilder) permission = permission.toPermission();
if (permission is! Permission) if (permission is! Permission)
throw new ArgumentError( throw new ArgumentError(
'createPermission must generate a Permission, whether synchronously or asynchronously.'); 'createPermission must generate a Permission, whether synchronously or asynchronously.');

View file

@ -18,9 +18,11 @@ class Permission {
/// permission, or if they are the resource [owner]. /// permission, or if they are the resource [owner].
/// ///
/// [getId] and [getOwner] are passed to [restrictToOwner], along with /// [getId] and [getOwner] are passed to [restrictToOwner], along with
/// [userKey] and [errorMessage]. /// [idField], [ownerField], [userKey] and [errorMessage].
HookedServiceEventListener toHook( HookedServiceEventListener toHook(
{String errorMessage, {String errorMessage,
String idField,
String ownerField,
String userKey, String userKey,
bool owner: false, bool owner: false,
getRoles(user), getRoles(user),
@ -41,6 +43,8 @@ class Permission {
// Try owner if the roles are not in-place // Try owner if the roles are not in-place
if (owner == true) { if (owner == true) {
var listener = restrictToOwner( var listener = restrictToOwner(
idField: idField,
ownerField: ownerField,
userKey: userKey, userKey: userKey,
errorMessage: errorMessage, errorMessage: errorMessage,
getId: getId, getId: getId,

View file

@ -1,5 +1,5 @@
name: angel_security name: angel_security
version: 0.0.5 version: 0.0.6
description: Angel middleware designed to enhance application security by patching common Web security holes. description: Angel middleware designed to enhance application security by patching common Web security holes.
author: Tobe O <thosakwe@gmail.com> author: Tobe O <thosakwe@gmail.com>
environment: environment: