From 771a4e8a5c22508259ea45e022dbc138fccdaf35 Mon Sep 17 00:00:00 2001 From: thosakwe Date: Fri, 13 Jan 2017 10:50:38 -0500 Subject: [PATCH] 17 --- README.md | 2 +- lib/src/auth_token.dart | 42 ++++++++++++++++++++++------ lib/src/middleware/require_auth.dart | 2 +- lib/src/plugin.dart | 12 ++++---- lib/src/strategies/local.dart | 4 +-- pubspec.yaml | 12 ++++---- test/auth_token_test.dart | 21 +++++++++++++- test/callback_test.dart | 2 +- 8 files changed, 72 insertions(+), 25 deletions(-) diff --git a/README.md b/README.md index 006fbbe8..f99f9b36 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # angel_auth -[![version 1.1.0-dev+16](https://img.shields.io/badge/version-1.1.0--dev+16-red.svg)](https://pub.dartlang.org/packages/angel_auth) +[![version 1.1.0-dev+17](https://img.shields.io/badge/version-1.1.0--dev+17-red.svg)](https://pub.dartlang.org/packages/angel_auth) ![build status](https://travis-ci.org/angel-dart/auth.svg?branch=master) A complete authentication plugin for Angel. Inspired by Passport. diff --git a/lib/src/auth_token.dart b/lib/src/auth_token.dart index 2883021c..2a37260b 100644 --- a/lib/src/auth_token.dart +++ b/lib/src/auth_token.dart @@ -11,27 +11,35 @@ class AuthToken { DateTime issuedAt; num lifeSpan; var userId; + Map payload = {}; AuthToken( - {this.ipAddress, this.lifeSpan: -1, this.userId, DateTime issuedAt}) { + {this.ipAddress, + this.lifeSpan: -1, + this.userId, + DateTime issuedAt, + Map payload: const {}}) { this.issuedAt = issuedAt ?? new DateTime.now(); + this.payload.addAll(payload ?? {}); } - factory AuthToken.fromJson(String json) => new AuthToken.fromMap(JSON.decode(json)); + factory AuthToken.fromJson(String json) => + new AuthToken.fromMap(JSON.decode(json)); factory AuthToken.fromMap(Map data) { return new AuthToken( ipAddress: data["aud"], lifeSpan: data["exp"], issuedAt: DateTime.parse(data["iat"]), - userId: data["sub"]); + userId: data["sub"], + payload: data["pld"] ?? {}); } factory AuthToken.validate(String jwt, Hmac hmac) { var split = jwt.split("."); if (split.length != 3) - throw new AngelHttpException.NotAuthenticated(message: "Invalid JWT."); + throw new AngelHttpException.notAuthenticated(message: "Invalid JWT."); // var headerString = new String.fromCharCodes(BASE64URL.decode(split[0])); var payloadString = new String.fromCharCodes(BASE64URL.decode(split[1])); @@ -39,7 +47,7 @@ class AuthToken { var signature = BASE64URL.encode(hmac.convert(data.codeUnits).bytes); if (signature != split[2]) - throw new AngelHttpException.NotAuthenticated( + throw new AngelHttpException.notAuthenticated( message: "JWT payload does not match hashed version."); return new AuthToken.fromMap(JSON.decode(payloadString)); @@ -47,19 +55,37 @@ class AuthToken { String serialize(Hmac hmac) { var headerString = BASE64URL.encode(JSON.encode(_header).codeUnits); - var payloadString = BASE64URL.encode(JSON.encode(this).codeUnits); + var payloadString = BASE64URL.encode(JSON.encode(toJson()).codeUnits); var data = headerString + "." + payloadString; var signature = hmac.convert(data.codeUnits).bytes; return data + "." + BASE64URL.encode(signature); } Map toJson() { - return new SplayTreeMap.from({ + return _splayify({ "iss": "angel_auth", "aud": ipAddress, "exp": lifeSpan, "iat": issuedAt.toIso8601String(), - "sub": userId + "sub": userId, + "pld": _splayify(payload) }); } } + +SplayTreeMap _splayify(Map map) { + var data = {}; + map.forEach((k, v) { + data[k] = _splay(v); + }); + return new SplayTreeMap.from(data); +} + +_splay(value) { + if (value is Iterable) { + return value.map(_splay).toList(); + } else if (value is Map) + return _splayify(value); + else + return value; +} diff --git a/lib/src/middleware/require_auth.dart b/lib/src/middleware/require_auth.dart index c9e74a02..da8343a5 100644 --- a/lib/src/middleware/require_auth.dart +++ b/lib/src/middleware/require_auth.dart @@ -10,7 +10,7 @@ class RequireAuthorizationMiddleware extends AngelMiddleware { bool _reject(ResponseContext res) { if (throwError) { res.statusCode = HttpStatus.FORBIDDEN; - throw new AngelHttpException.Forbidden(); + throw new AngelHttpException.forbidden(); } else return false; } diff --git a/lib/src/plugin.dart b/lib/src/plugin.dart index 696719a1..4d9ca683 100644 --- a/lib/src/plugin.dart +++ b/lib/src/plugin.dart @@ -95,7 +95,7 @@ class AngelAuth extends AngelPlugin { } if (req.ip != null && req.ip != token.ipAddress) - throw new AngelHttpException.Forbidden( + throw new AngelHttpException.forbidden( message: "JWT cannot be accessed from this IP address."); } @@ -107,7 +107,7 @@ class AngelAuth extends AngelPlugin { token.issuedAt.add(new Duration(milliseconds: token.lifeSpan)); if (!token.issuedAt.isAfter(new DateTime.now())) - throw new AngelHttpException.Forbidden(message: "Expired JWT."); + throw new AngelHttpException.forbidden(message: "Expired JWT."); } else if (debug) { print('This token has an infinite life span.'); } @@ -161,7 +161,7 @@ class AngelAuth extends AngelPlugin { if (debug) print('Found JWT: $jwt'); if (jwt == null) { - throw new AngelHttpException.Forbidden(message: "No JWT provided"); + throw new AngelHttpException.forbidden(message: "No JWT provided"); } else { var token = new AuthToken.validate(jwt, _hs256); @@ -174,7 +174,7 @@ class AngelAuth extends AngelPlugin { .ip}'); if (req.ip != token.ipAddress) - throw new AngelHttpException.Forbidden( + throw new AngelHttpException.forbidden( message: "JWT cannot be accessed from this IP address."); } @@ -216,7 +216,7 @@ class AngelAuth extends AngelPlugin { } if (e is AngelHttpException) rethrow; - throw new AngelHttpException.BadRequest(message: "Malformed JWT"); + throw new AngelHttpException.badRequest(message: "Malformed JWT"); } } @@ -262,7 +262,7 @@ class AngelAuth extends AngelPlugin { } Future authenticationFailure(RequestContext req, ResponseContext res) async { - throw new AngelHttpException.NotAuthenticated(); + throw new AngelHttpException.notAuthenticated(); } logout([AngelAuthOptions options]) { diff --git a/lib/src/strategies/local.dart b/lib/src/strategies/local.dart index ce468b0a..1b4d9e95 100644 --- a/lib/src/strategies/local.dart +++ b/lib/src/strategies/local.dart @@ -56,7 +56,7 @@ class LocalAuthStrategy extends AuthStrategy { verificationResult = await verifier(usrPassMatch.group(1), usrPassMatch.group(2)); } else - throw new AngelHttpException.BadRequest(errors: [invalidMessage]); + throw new AngelHttpException.badRequest(errors: [invalidMessage]); } } @@ -86,7 +86,7 @@ class LocalAuthStrategy extends AuthStrategy { } else if (verificationResult != null && verificationResult != false) { return verificationResult; } else { - throw new AngelHttpException.NotAuthenticated(); + throw new AngelHttpException.notAuthenticated(); } } } diff --git a/pubspec.yaml b/pubspec.yaml index 7c81491e..bdf93359 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,11 +1,13 @@ name: angel_auth description: A complete authentication plugin for Angel. -version: 1.0.0-dev+16 +version: 1.0.0-dev+17 author: Tobe O homepage: https://github.com/angel-dart/angel_auth +environment: + sdk: ">=1.19.0" dependencies: - angel_framework: ">=1.0.0-dev <2.0.0" - crypto: ">=2.0.0 <3.0.0" + angel_framework: ^1.0.0-dev + crypto: ^2.0.0 dev_dependencies: - http: ">= 0.11.3 < 0.12.0" - test: ">= 0.12.13 < 0.13.0" + http: ^0.11.0 + test: ^0.12.0 diff --git a/test/auth_token_test.dart b/test/auth_token_test.dart index 34a3dd3d..5eeb8c77 100644 --- a/test/auth_token_test.dart +++ b/test/auth_token_test.dart @@ -12,5 +12,24 @@ main() async { var parsed = new AuthToken.validate(jwt, hmac); print(parsed.toJson()); + expect(parsed.toJson()['aud'], equals(token.ipAddress)); + expect(parsed.toJson()['sub'], equals(token.userId)); }); -} \ No newline at end of file + + test('custom payload', () { + var token = + new AuthToken(ipAddress: "localhost", userId: "thosakwe", payload: { + "foo": "bar", + "baz": { + "one": 1, + "franken": ["stein"] + } + }); + var jwt = token.serialize(hmac); + print(jwt); + + var parsed = new AuthToken.validate(jwt, hmac); + print(parsed.toJson()); + expect(parsed.toJson()['pld'], equals(token.payload)); + }); +} diff --git a/test/callback_test.dart b/test/callback_test.dart index 8dca3b6e..70173613 100644 --- a/test/callback_test.dart +++ b/test/callback_test.dart @@ -43,7 +43,7 @@ main() { '/login', auth.authenticate('local', new AngelAuthOptions(callback: (req, res, token) { - return res + res ..write('Hello!') ..end(); })));