platform/test/hooks_test.dart

285 lines
8.1 KiB
Dart
Raw Normal View History

2017-01-28 20:29:20 +00:00
import 'package:angel_framework/angel_framework.dart';
import 'package:angel_security/angel_security.dart';
import 'package:angel_security/hooks.dart' as hooks;
import 'package:angel_test/angel_test.dart';
import 'package:crypto/crypto.dart';
import 'package:test/test.dart';
main() {
Angel app;
TestClient client;
setUp(() async {
2019-04-20 14:53:52 +00:00
app = Angel()
..fallback((req, res) async {
2017-01-28 20:29:20 +00:00
var xUser = req.headers.value('X-User');
2019-04-20 14:53:52 +00:00
if (xUser != null) {
req.container.registerSingleton(
User(id: xUser, roles: xUser == 'John' ? ['foo:bar'] : []));
}
2017-01-28 20:29:20 +00:00
return true;
});
app
2019-04-20 14:53:52 +00:00
..use('/user_data', UserDataService())
..use('/artists', ArtistService())
..use('/roled', RoledService());
2017-01-28 20:29:20 +00:00
2019-04-20 14:53:52 +00:00
(app.findService('user_data') as HookedService)
2017-01-28 20:29:20 +00:00
..beforeIndexed.listen(hooks.queryWithCurrentUser())
..beforeCreated.listen(hooks.hashPassword());
2019-04-20 14:53:52 +00:00
app.findService('artists') as HookedService
2017-01-28 20:29:20 +00:00
..beforeIndexed.listen(hooks.restrictToAuthenticated())
..beforeRead.listen(hooks.restrictToOwner())
..beforeCreated.listen(hooks.associateCurrentUser());
2019-04-20 14:53:52 +00:00
(app.findService('roled') as HookedService)
..beforeIndexed.listen(Permission('foo:*').toHook())
..beforeRead.listen(Permission('foo:*').toHook(owner: true));
2017-01-28 20:29:20 +00:00
2017-12-22 13:35:46 +00:00
var errorHandler = app.errorHandler;
app.errorHandler = (e, req, res) {
print(e.toJson());
print(e.stackTrace);
return errorHandler(e, req, res);
};
2017-01-28 20:29:20 +00:00
client = await connectTo(app);
});
tearDown(() => client.close());
group('associateCurrentUser', () {
test('fail', () async {
try {
var response = await client.service('artists').create({'foo': 'bar'});
print(response);
2019-04-20 14:53:52 +00:00
throw StateError('Creating without userId bad request');
2017-01-28 20:29:20 +00:00
} catch (e) {
print(e);
2019-04-20 14:53:52 +00:00
expect(e, const TypeMatcher<AngelHttpException>());
2017-01-28 20:29:20 +00:00
var err = e as AngelHttpException;
expect(err.statusCode, equals(403));
}
});
test('succeed', () async {
var response = await client
.post('/artists', headers: {'X-User': 'John'}, body: {'foo': 'bar'});
print('Response: ${response.body}');
2017-03-29 02:14:47 +00:00
print('Status: ${response.statusCode}');
expect(response, allOf(hasStatus(201), isJson({'foo': 'bar'})));
2017-01-28 20:29:20 +00:00
});
});
group('queryWithCurrentUser', () {
test('fail', () async {
try {
var response = await client.service('user_data').index();
print(response);
2019-04-20 14:53:52 +00:00
throw StateError('Indexing without user forbidden');
2017-01-28 20:29:20 +00:00
} catch (e) {
print(e);
2019-04-20 14:53:52 +00:00
expect(e, const TypeMatcher<AngelHttpException>());
2017-01-28 20:29:20 +00:00
var err = e as AngelHttpException;
expect(err.statusCode, equals(403));
}
});
test('succeed', () async {
var response = await client.get('user_data', headers: {'X-User': 'John'});
print('Response: ${response.body}');
expect(response, allOf(hasStatus(200), isJson(['foo', 'bar'])));
});
});
test('hashPassword', () async {
var response = await client
.service('user_data')
.create({'username': 'foo', 'password': 'jdoe1'});
print('Response: ${response}');
expect(response, equals({'foo': 'bar'}));
});
group('restrictToAuthenticated', () {
test('fail', () async {
try {
var response = await client.service('artists').index();
print(response);
2019-04-20 14:53:52 +00:00
throw StateError('Indexing without user forbidden');
2017-01-28 20:29:20 +00:00
} catch (e) {
print(e);
2019-04-20 14:53:52 +00:00
expect(e, const TypeMatcher<AngelHttpException>());
2017-01-28 20:29:20 +00:00
var err = e as AngelHttpException;
expect(err.statusCode, equals(403));
}
});
test('succeed', () async {
var response = await client.get('/artists', headers: {'X-User': 'John'});
print('Response: ${response.body}');
expect(
response,
allOf(
hasStatus(200),
isJson([
{
"id": "king_of_pop",
"userId": "John",
"name": "Michael Jackson"
},
{"id": "raymond", "userId": "Bob", "name": "Usher"}
])));
});
});
group('restrictToOwner', () {
test('fail', () async {
try {
var response = await client.service('artists').read('king_of_pop');
print(response);
2019-04-20 14:53:52 +00:00
throw StateError('Reading without owner forbidden');
2017-01-28 20:29:20 +00:00
} catch (e) {
print(e);
2019-04-20 14:53:52 +00:00
expect(e, const TypeMatcher<AngelHttpException>());
2017-01-28 20:29:20 +00:00
var err = e as AngelHttpException;
expect(err.statusCode, equals(401));
}
});
test('succeed', () async {
var response =
await client.get('/artists/king_of_pop', headers: {'X-User': 'John'});
print('Response: ${response.body}');
expect(
response,
allOf(
hasStatus(200),
isJson({
"id": "king_of_pop",
"userId": "John",
"name": "Michael Jackson"
})));
});
});
group('permission restrict', () {
test('fail', () async {
try {
var response = await client.service('roled').index();
print(response);
2019-04-20 14:53:52 +00:00
throw StateError('Reading without roles forbidden');
2017-01-28 20:29:20 +00:00
} catch (e) {
print(e);
2019-04-20 14:53:52 +00:00
expect(e, const TypeMatcher<AngelHttpException>());
2017-01-28 20:29:20 +00:00
var err = e as AngelHttpException;
expect(err.statusCode, equals(403));
}
});
test('succeed', () async {
var response =
await client.get('/roled/king_of_pop', headers: {'X-User': 'John'});
print('Response: ${response.body}');
expect(
response,
allOf(
hasStatus(200),
isJson({
"id": "king_of_pop",
"userId": "John",
"name": "Michael Jackson"
})));
});
test('owner', () async {
var response =
await client.get('/roled/raymond', headers: {'X-User': 'Bob'});
print('Response: ${response.body}');
expect(
response,
allOf(hasStatus(200),
isJson({"id": "raymond", "userId": "Bob", "name": "Usher"})));
});
});
}
class User {
String id;
List<String> roles;
2019-04-20 14:53:52 +00:00
User({this.id, this.roles = const []});
2017-01-28 20:29:20 +00:00
}
class UserDataService extends Service {
static const Map<String, List> _data = const {
'John': const ['foo', 'bar']
};
@override
index([Map params]) async {
print('Params: $params');
if (params?.containsKey('query') != true)
2019-04-20 14:53:52 +00:00
throw AngelHttpException.badRequest(message: 'query required');
2017-01-28 20:29:20 +00:00
String name = params['query']['userId']?.toString();
if (!_data.containsKey(name))
2019-04-20 14:53:52 +00:00
throw AngelHttpException.notFound(
2017-01-28 20:29:20 +00:00
message: "No data found for user '$name'.");
return _data[name];
}
@override
create(data, [Map params]) async {
if (data is! Map || !data.containsKey('password'))
2019-04-20 14:53:52 +00:00
throw AngelHttpException.badRequest(message: 'Required password!');
2017-01-28 20:29:20 +00:00
var expected =
2019-04-20 14:53:52 +00:00
String.fromCharCodes(sha256.convert('jdoe1'.codeUnits).bytes);
2017-01-28 20:29:20 +00:00
if (data['password'] != (expected))
2019-04-20 14:53:52 +00:00
throw AngelHttpException.conflict(message: 'Passwords do not match.');
2017-01-28 20:29:20 +00:00
return {'foo': 'bar'};
}
}
class ArtistService extends Service {
static const List<Artist> _ARTISTS = const [_MICHAEL_JACKSON, _USHER];
@override
index([params]) async => _ARTISTS;
@override
read(id, [params]) async => _ARTISTS.firstWhere((a) => a.id == id);
@override
create(data, [params]) async {
if (data is! Map || !data.containsKey('userId'))
2019-04-20 14:53:52 +00:00
throw AngelHttpException.badRequest(message: 'Required userId');
2017-01-28 20:29:20 +00:00
return {'foo': 'bar'};
}
}
class Artist {
final String id, userId, name;
const Artist({this.id, this.userId, this.name});
}
const Artist _USHER = const Artist(id: 'raymond', userId: 'Bob', name: 'Usher');
const Artist _MICHAEL_JACKSON =
const Artist(id: 'king_of_pop', userId: 'John', name: 'Michael Jackson');
class RoledService extends Service {
@override
2017-12-22 13:35:46 +00:00
index([params]) async {
2017-01-28 20:29:20 +00:00
return ['foo'];
}
@override
read(id, [params]) async =>
ArtistService._ARTISTS.firstWhere((a) => a.id == id);
}