diff --git a/lib/src/plugin.dart b/lib/src/plugin.dart index c1a8dcf5..06e040c8 100644 --- a/lib/src/plugin.dart +++ b/lib/src/plugin.dart @@ -19,6 +19,7 @@ class AngelAuth extends AngelPlugin { RequireAuthorizationMiddleware _requireAuth = new RequireAuthorizationMiddleware(); bool enforceIp; + String reviveTokenEndpoint; List strategies = []; UserSerializer serializer; UserDeserializer deserializer; @@ -31,7 +32,7 @@ class AngelAuth extends AngelPlugin { return new String.fromCharCodes(chars); } - AngelAuth({String jwtKey, num jwtLifeSpan, this.enforceIp}) : super() { + AngelAuth({String jwtKey, num jwtLifeSpan, this.enforceIp, this.reviveTokenEndpoint: "/auth/token"}) : super() { _hs256 = new Hmac(sha256, (jwtKey ?? _randomString()).codeUnits); _jwtLifeSpan = jwtLifeSpan ?? -1; } @@ -43,17 +44,20 @@ class AngelAuth extends AngelPlugin { app.before.add(_decodeJwt); app.registerMiddleware('auth', _requireAuth); + + if (reviveTokenEndpoint != null) { + app.post(reviveTokenEndpoint, _reviveJwt); + } } _decodeJwt(RequestContext req, ResponseContext res) async { - String jwt = null; - if (req.headers.value("Authorization") != null) { - var jwt = - req.headers.value("Authorization").replaceAll(_rgxBearer, "").trim(); - } else if (req.cookies.any((cookie) => cookie.name == "token")) { - jwt = req.cookies.firstWhere((cookie) => cookie.name == "token").value; + if (req.path == reviveTokenEndpoint) { + // Shouldn't block invalid JWT if we are reviving it + return true; } + String jwt = _getJwt(req); + if (jwt != null) { var token = new AuthToken.validate(jwt, _hs256); @@ -76,6 +80,50 @@ class AngelAuth extends AngelPlugin { return true; } + + _getJwt(RequestContext req) { + if (req.headers.value("Authorization") != null) { + return req.headers.value("Authorization").replaceAll(_rgxBearer, "").trim(); + } else if (req.cookies.any((cookie) => cookie.name == "token")) { + return req.cookies.firstWhere((cookie) => cookie.name == "token").value; + } + + return null; + } + + _reviveJwt(RequestContext req, ResponseContext res) async { + try { + var jwt = _getJwt(req); + + if (jwt == null) { + throw new AngelHttpException.Forbidden(message: "No JWT provided"); + } else { + var token = new AuthToken.validate(jwt, _hs256); + + if (enforceIp) { + if (req.ip != token.ipAddress) + throw new AngelHttpException.Forbidden( + message: "JWT cannot be accessed from this IP address."); + } + + if (token.lifeSpan > -1) { + token.issuedAt.add(new Duration(milliseconds: token.lifeSpan)); + + if (!token.issuedAt.isAfter(new DateTime.now())) { + // Extend its lifespan by changing iat + token.issuedAt = new DateTime.now(); + } + } + + return token.toJson(); + } + } catch(e) { + if (e is AngelHttpException) + rethrow; + throw new AngelHttpException.BadRequest(message: "Malformed JWT"); + } + } + authenticate(String type, [AngelAuthOptions options]) { return (RequestContext req, ResponseContext res) async { AuthStrategy strategy = diff --git a/pubspec.yaml b/pubspec.yaml index 8d1d3d7c..49965229 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+7 +version: 1.0.0-dev+8 author: Tobe O homepage: https://github.com/angel-dart/angel_auth dependencies: