Debug
This commit is contained in:
parent
abebd65e7d
commit
afb554fba0
6 changed files with 135 additions and 12 deletions
17
.idea/angel_auth.iml
Normal file
17
.idea/angel_auth.iml
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<module type="WEB_MODULE" version="4">
|
||||||
|
<component name="NewModuleRootManager">
|
||||||
|
<content url="file://$MODULE_DIR$">
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/.pub" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/.tmp" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/packages" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/temp" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/test/packages" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/tmp" />
|
||||||
|
</content>
|
||||||
|
<orderEntry type="inheritedJdk" />
|
||||||
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
<orderEntry type="library" name="Dart SDK" level="application" />
|
||||||
|
<orderEntry type="library" name="Dart Packages" level="project" />
|
||||||
|
</component>
|
||||||
|
</module>
|
38
.idea/misc.xml
Normal file
38
.idea/misc.xml
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="JavaScriptSettings">
|
||||||
|
<option name="languageLevel" value="ES6" />
|
||||||
|
</component>
|
||||||
|
<component name="ProjectInspectionProfilesVisibleTreeState">
|
||||||
|
<entry key="Project Default">
|
||||||
|
<profile-state>
|
||||||
|
<expanded-state>
|
||||||
|
<State>
|
||||||
|
<id />
|
||||||
|
</State>
|
||||||
|
<State>
|
||||||
|
<id>General</id>
|
||||||
|
</State>
|
||||||
|
<State>
|
||||||
|
<id>XPath</id>
|
||||||
|
</State>
|
||||||
|
</expanded-state>
|
||||||
|
<selected-state>
|
||||||
|
<State>
|
||||||
|
<id>AngularJS</id>
|
||||||
|
</State>
|
||||||
|
</selected-state>
|
||||||
|
</profile-state>
|
||||||
|
</entry>
|
||||||
|
</component>
|
||||||
|
<component name="ProjectLevelVcsManager" settingsEditedManually="false">
|
||||||
|
<OptionsSetting value="true" id="Add" />
|
||||||
|
<OptionsSetting value="true" id="Remove" />
|
||||||
|
<OptionsSetting value="true" id="Checkout" />
|
||||||
|
<OptionsSetting value="true" id="Update" />
|
||||||
|
<OptionsSetting value="true" id="Status" />
|
||||||
|
<OptionsSetting value="true" id="Edit" />
|
||||||
|
<ConfirmationsSetting value="0" id="Add" />
|
||||||
|
<ConfirmationsSetting value="0" id="Remove" />
|
||||||
|
</component>
|
||||||
|
</project>
|
8
.idea/modules.xml
Normal file
8
.idea/modules.xml
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ProjectModuleManager">
|
||||||
|
<modules>
|
||||||
|
<module fileurl="file://$PROJECT_DIR$/.idea/angel_auth.iml" filepath="$PROJECT_DIR$/.idea/angel_auth.iml" />
|
||||||
|
</modules>
|
||||||
|
</component>
|
||||||
|
</project>
|
|
@ -18,13 +18,18 @@ class AngelAuth extends AngelPlugin {
|
||||||
final RegExp _rgxBearer = new RegExp(r"^Bearer");
|
final RegExp _rgxBearer = new RegExp(r"^Bearer");
|
||||||
RequireAuthorizationMiddleware _requireAuth =
|
RequireAuthorizationMiddleware _requireAuth =
|
||||||
new RequireAuthorizationMiddleware();
|
new RequireAuthorizationMiddleware();
|
||||||
|
String middlewareName;
|
||||||
|
bool debug;
|
||||||
bool enforceIp;
|
bool enforceIp;
|
||||||
String reviveTokenEndpoint;
|
String reviveTokenEndpoint;
|
||||||
List<AuthStrategy> strategies = [];
|
List<AuthStrategy> strategies = [];
|
||||||
UserSerializer serializer;
|
UserSerializer serializer;
|
||||||
UserDeserializer deserializer;
|
UserDeserializer deserializer;
|
||||||
|
|
||||||
String _randomString({int length: 32, String validChars: "ABCDEFHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_"}) {
|
String _randomString(
|
||||||
|
{int length: 32,
|
||||||
|
String validChars:
|
||||||
|
"ABCDEFHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_"}) {
|
||||||
var chars = <int>[];
|
var chars = <int>[];
|
||||||
|
|
||||||
while (chars.length < length) chars.add(_random.nextInt(validChars.length));
|
while (chars.length < length) chars.add(_random.nextInt(validChars.length));
|
||||||
|
@ -32,7 +37,14 @@ class AngelAuth extends AngelPlugin {
|
||||||
return new String.fromCharCodes(chars);
|
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);
|
_hs256 = new Hmac(sha256, (jwtKey ?? _randomString()).codeUnits);
|
||||||
_jwtLifeSpan = jwtLifeSpan ?? -1;
|
_jwtLifeSpan = jwtLifeSpan ?? -1;
|
||||||
}
|
}
|
||||||
|
@ -43,7 +55,7 @@ class AngelAuth extends AngelPlugin {
|
||||||
if (runtimeType != AngelAuth) app.container.singleton(this, as: AngelAuth);
|
if (runtimeType != AngelAuth) app.container.singleton(this, as: AngelAuth);
|
||||||
|
|
||||||
app.before.add(_decodeJwt);
|
app.before.add(_decodeJwt);
|
||||||
app.registerMiddleware('auth', _requireAuth);
|
app.registerMiddleware(middlewareName, _requireAuth);
|
||||||
|
|
||||||
if (reviveTokenEndpoint != null) {
|
if (reviveTokenEndpoint != null) {
|
||||||
app.post(reviveTokenEndpoint, _reviveJwt);
|
app.post(reviveTokenEndpoint, _reviveJwt);
|
||||||
|
@ -51,9 +63,13 @@ class AngelAuth extends AngelPlugin {
|
||||||
}
|
}
|
||||||
|
|
||||||
_decodeJwt(RequestContext req, ResponseContext res) async {
|
_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
|
// 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);
|
String jwt = _getJwt(req);
|
||||||
|
@ -80,11 +96,22 @@ class AngelAuth extends AngelPlugin {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
_getJwt(RequestContext req) {
|
_getJwt(RequestContext req) {
|
||||||
|
if (debug) {
|
||||||
|
print('Attempting to parse JWT');
|
||||||
|
}
|
||||||
|
|
||||||
if (req.headers.value("Authorization") != null) {
|
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")) {
|
} else if (req.cookies.any((cookie) => cookie.name == "token")) {
|
||||||
|
print('Request has "token" cookie...');
|
||||||
return req.cookies.firstWhere((cookie) => cookie.name == "token").value;
|
return req.cookies.firstWhere((cookie) => cookie.name == "token").value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -93,33 +120,64 @@ class AngelAuth extends AngelPlugin {
|
||||||
|
|
||||||
_reviveJwt(RequestContext req, ResponseContext res) async {
|
_reviveJwt(RequestContext req, ResponseContext res) async {
|
||||||
try {
|
try {
|
||||||
|
if (debug)
|
||||||
|
print('Attempting to revive JWT...');
|
||||||
|
|
||||||
var jwt = _getJwt(req);
|
var jwt = _getJwt(req);
|
||||||
|
|
||||||
|
if (debug)
|
||||||
|
print('Found JWT: $jwt');
|
||||||
|
|
||||||
if (jwt == null) {
|
if (jwt == null) {
|
||||||
throw new AngelHttpException.Forbidden(message: "No JWT provided");
|
throw new AngelHttpException.Forbidden(message: "No JWT provided");
|
||||||
} else {
|
} else {
|
||||||
var token = new AuthToken.validate(jwt, _hs256);
|
var token = new AuthToken.validate(jwt, _hs256);
|
||||||
|
|
||||||
|
if (debug)
|
||||||
|
print('Validated and deserialized: $token');
|
||||||
|
|
||||||
if (enforceIp) {
|
if (enforceIp) {
|
||||||
|
if (debug)
|
||||||
|
print('Token IP: ${token.ipAddress}. Current request sent from: ${req.ip}');
|
||||||
|
|
||||||
if (req.ip != token.ipAddress)
|
if (req.ip != token.ipAddress)
|
||||||
throw new AngelHttpException.Forbidden(
|
throw new AngelHttpException.Forbidden(
|
||||||
message: "JWT cannot be accessed from this IP address.");
|
message: "JWT cannot be accessed from this IP address.");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (token.lifeSpan > -1) {
|
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));
|
token.issuedAt.add(new Duration(milliseconds: token.lifeSpan));
|
||||||
|
|
||||||
if (!token.issuedAt.isAfter(new DateTime.now())) {
|
if (!token.issuedAt.isAfter(new DateTime.now())) {
|
||||||
|
print('Token has indeed expired! Resetting assignment date to current timestamp...');
|
||||||
// Extend its lifespan by changing iat
|
// Extend its lifespan by changing iat
|
||||||
token.issuedAt = new DateTime.now();
|
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();
|
return token.toJson();
|
||||||
}
|
}
|
||||||
} catch(e) {
|
} catch (e, st) {
|
||||||
if (e is AngelHttpException)
|
if (debug) {
|
||||||
rethrow;
|
print('An error occurred while reviving this token.');
|
||||||
|
print(e);
|
||||||
|
print(st);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (e is AngelHttpException) rethrow;
|
||||||
throw new AngelHttpException.BadRequest(message: "Malformed JWT");
|
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("*/*") ||
|
||||||
req.headers.value("accept").contains("application/*"))) {
|
req.headers.value("accept").contains("application/*"))) {
|
||||||
return {"data": result, "token": jwt};
|
return {"data": result, "token": jwt};
|
||||||
} else if (options != null && options.successRedirect != null &&
|
} else if (options != null &&
|
||||||
|
options.successRedirect != null &&
|
||||||
options.successRedirect.isNotEmpty) {
|
options.successRedirect.isNotEmpty) {
|
||||||
return res.redirect(options.successRedirect, code: HttpStatus.OK);
|
return res.redirect(options.successRedirect, code: HttpStatus.OK);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
name: angel_auth
|
name: angel_auth
|
||||||
description: A complete authentication plugin for Angel.
|
description: A complete authentication plugin for Angel.
|
||||||
version: 1.0.0-dev+8
|
version: 1.0.0-dev+9
|
||||||
author: Tobe O <thosakwe@gmail.com>
|
author: Tobe O <thosakwe@gmail.com>
|
||||||
homepage: https://github.com/angel-dart/angel_auth
|
homepage: https://github.com/angel-dart/angel_auth
|
||||||
dependencies:
|
dependencies:
|
||||||
|
|
1
test/packages
Symbolic link
1
test/packages
Symbolic link
|
@ -0,0 +1 @@
|
||||||
|
../packages
|
Loading…
Reference in a new issue