diff --git a/.idea/angel_auth.iml b/.idea/angel_auth.iml
new file mode 100644
index 00000000..e7d9f5eb
--- /dev/null
+++ b/.idea/angel_auth.iml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
new file mode 100644
index 00000000..eac82ac0
--- /dev/null
+++ b/.idea/misc.xml
@@ -0,0 +1,38 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ General
+
+
+ XPath
+
+
+
+
+ AngularJS
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
new file mode 100644
index 00000000..f63a15fb
--- /dev/null
+++ b/.idea/modules.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/lib/src/plugin.dart b/lib/src/plugin.dart
index 06e040c8..8a70a7e2 100644
--- a/lib/src/plugin.dart
+++ b/lib/src/plugin.dart
@@ -18,13 +18,18 @@ class AngelAuth extends AngelPlugin {
final RegExp _rgxBearer = new RegExp(r"^Bearer");
RequireAuthorizationMiddleware _requireAuth =
new RequireAuthorizationMiddleware();
+ String middlewareName;
+ bool debug;
bool enforceIp;
String reviveTokenEndpoint;
List strategies = [];
UserSerializer serializer;
UserDeserializer deserializer;
- String _randomString({int length: 32, String validChars: "ABCDEFHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_"}) {
+ String _randomString(
+ {int length: 32,
+ String validChars:
+ "ABCDEFHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_"}) {
var chars = [];
while (chars.length < length) chars.add(_random.nextInt(validChars.length));
@@ -32,7 +37,14 @@ class AngelAuth extends AngelPlugin {
return new String.fromCharCodes(chars);
}
- AngelAuth({String jwtKey, num jwtLifeSpan, this.enforceIp, this.reviveTokenEndpoint: "/auth/token"}) : super() {
+ AngelAuth(
+ {String jwtKey,
+ num jwtLifeSpan,
+ this.debug: false,
+ this.enforceIp: true,
+ this.middlewareName: 'auth',
+ this.reviveTokenEndpoint: "/auth/token"})
+ : super() {
_hs256 = new Hmac(sha256, (jwtKey ?? _randomString()).codeUnits);
_jwtLifeSpan = jwtLifeSpan ?? -1;
}
@@ -43,7 +55,7 @@ class AngelAuth extends AngelPlugin {
if (runtimeType != AngelAuth) app.container.singleton(this, as: AngelAuth);
app.before.add(_decodeJwt);
- app.registerMiddleware('auth', _requireAuth);
+ app.registerMiddleware(middlewareName, _requireAuth);
if (reviveTokenEndpoint != null) {
app.post(reviveTokenEndpoint, _reviveJwt);
@@ -51,9 +63,13 @@ class AngelAuth extends AngelPlugin {
}
_decodeJwt(RequestContext req, ResponseContext res) async {
- if (req.path == reviveTokenEndpoint) {
+ if (req.method == "POST" && req.path == reviveTokenEndpoint) {
// Shouldn't block invalid JWT if we are reviving it
- return true;
+
+ if (debug)
+ print('Token revival endpoint accessed.');
+
+ return await _reviveJwt(req, res);
}
String jwt = _getJwt(req);
@@ -80,11 +96,22 @@ class AngelAuth extends AngelPlugin {
return true;
}
-
_getJwt(RequestContext req) {
+ if (debug) {
+ print('Attempting to parse JWT');
+ }
+
if (req.headers.value("Authorization") != null) {
- return req.headers.value("Authorization").replaceAll(_rgxBearer, "").trim();
+ if (debug) {
+ print('Found Auth header');
+ }
+
+ return req.headers
+ .value("Authorization")
+ .replaceAll(_rgxBearer, "")
+ .trim();
} else if (req.cookies.any((cookie) => cookie.name == "token")) {
+ print('Request has "token" cookie...');
return req.cookies.firstWhere((cookie) => cookie.name == "token").value;
}
@@ -93,33 +120,64 @@ class AngelAuth extends AngelPlugin {
_reviveJwt(RequestContext req, ResponseContext res) async {
try {
+ if (debug)
+ print('Attempting to revive JWT...');
+
var jwt = _getJwt(req);
+ if (debug)
+ print('Found JWT: $jwt');
+
if (jwt == null) {
throw new AngelHttpException.Forbidden(message: "No JWT provided");
} else {
var token = new AuthToken.validate(jwt, _hs256);
+ if (debug)
+ print('Validated and deserialized: $token');
+
if (enforceIp) {
+ if (debug)
+ print('Token IP: ${token.ipAddress}. Current request sent from: ${req.ip}');
+
if (req.ip != token.ipAddress)
throw new AngelHttpException.Forbidden(
message: "JWT cannot be accessed from this IP address.");
}
if (token.lifeSpan > -1) {
+ if (debug) {
+ print('Checking if token has expired... Life span is ${token.lifeSpan}');
+ }
+
token.issuedAt.add(new Duration(milliseconds: token.lifeSpan));
if (!token.issuedAt.isAfter(new DateTime.now())) {
+ print('Token has indeed expired! Resetting assignment date to current timestamp...');
// Extend its lifespan by changing iat
token.issuedAt = new DateTime.now();
+ } else if (debug) {
+ print('Token has not expired yet.');
}
+ } else if(debug) {
+ print('This token never expires, so it is still valid.');
}
+ if (debug) {
+ print('Final, valid token: ${token.toJson()}');
+ }
+
+ res.cookies.add(new Cookie('token', token.serialize(_hs256)));
return token.toJson();
}
- } catch(e) {
- if (e is AngelHttpException)
- rethrow;
+ } catch (e, st) {
+ if (debug) {
+ print('An error occurred while reviving this token.');
+ print(e);
+ print(st);
+ }
+
+ if (e is AngelHttpException) rethrow;
throw new AngelHttpException.BadRequest(message: "Malformed JWT");
}
}
@@ -144,7 +202,8 @@ class AngelAuth extends AngelPlugin {
req.headers.value("accept").contains("*/*") ||
req.headers.value("accept").contains("application/*"))) {
return {"data": result, "token": jwt};
- } else if (options != null && options.successRedirect != null &&
+ } else if (options != null &&
+ options.successRedirect != null &&
options.successRedirect.isNotEmpty) {
return res.redirect(options.successRedirect, code: HttpStatus.OK);
}
diff --git a/pubspec.yaml b/pubspec.yaml
index 49965229..d5d790eb 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -1,6 +1,6 @@
name: angel_auth
description: A complete authentication plugin for Angel.
-version: 1.0.0-dev+8
+version: 1.0.0-dev+9
author: Tobe O
homepage: https://github.com/angel-dart/angel_auth
dependencies:
diff --git a/test/packages b/test/packages
new file mode 120000
index 00000000..a16c4050
--- /dev/null
+++ b/test/packages
@@ -0,0 +1 @@
+../packages
\ No newline at end of file