Remove "new"
This commit is contained in:
parent
f67fd7b99b
commit
b6acfb1573
15 changed files with 114 additions and 112 deletions
|
@ -1,3 +1,6 @@
|
|||
# 2.1.3
|
||||
* Use `await` on redirects, etc.
|
||||
|
||||
# 2.1.2
|
||||
* Change empty cookie string to have double quotes (thanks @korsvanloon).
|
||||
|
||||
|
|
|
@ -17,10 +17,10 @@ Ensure you have read the [wiki](https://github.com/angel-dart/auth/wiki).
|
|||
|
||||
```dart
|
||||
configureServer(Angel app) async {
|
||||
var auth = new AngelAuth();
|
||||
var auth = AngelAuth();
|
||||
auth.serializer = ...;
|
||||
auth.deserializer = ...;
|
||||
auth.strategies['local'] = new LocalAuthStrategy(...);
|
||||
auth.strategies['local'] = LocalAuthStrategy(...);
|
||||
|
||||
// POST route to handle username+password
|
||||
app.post('/local', auth.authenticate('local'));
|
||||
|
@ -55,7 +55,7 @@ in this package.
|
|||
configureServer(Angel app) async {
|
||||
var handler = auth.authenticate(
|
||||
'facebook',
|
||||
new AngelAuthOptions(callback: confirmPopupAuthentication()));
|
||||
AngelAuthOptions(callback: confirmPopupAuthentication()));
|
||||
app.get('/auth/facebook', handler);
|
||||
|
||||
// Use a comma to try multiple strategies!!!
|
||||
|
|
|
@ -4,8 +4,8 @@ import 'package:angel_framework/angel_framework.dart';
|
|||
import 'package:angel_framework/http.dart';
|
||||
|
||||
main() async {
|
||||
var app = new Angel();
|
||||
var auth = new AngelAuth<User>();
|
||||
var app = Angel();
|
||||
var auth = AngelAuth<User>();
|
||||
|
||||
auth.serializer = (user) => user.id;
|
||||
|
||||
|
@ -14,7 +14,7 @@ main() async {
|
|||
// Middleware to decode JWT's and inject a user object...
|
||||
app.fallback(auth.decodeJwt);
|
||||
|
||||
auth.strategies['local'] = new LocalAuthStrategy((username, password) {
|
||||
auth.strategies['local'] = LocalAuthStrategy((username, password) {
|
||||
// Retrieve a user somehow...
|
||||
// If authentication succeeds, return a User object.
|
||||
//
|
||||
|
@ -23,7 +23,7 @@ main() async {
|
|||
|
||||
app.post('/auth/local', auth.authenticate('local'));
|
||||
|
||||
var http = new AngelHttp(app);
|
||||
var http = AngelHttp(app);
|
||||
await http.startServer('127.0.0.1', 3000);
|
||||
|
||||
print('Listening at http://127.0.0.1:3000');
|
||||
|
@ -35,5 +35,5 @@ class User {
|
|||
|
||||
Future<User> fetchAUserByIdSomehow(id) async {
|
||||
// Fetch a user somehow...
|
||||
throw new UnimplementedError();
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@ String decodeBase64(String str) {
|
|||
|
||||
class AuthToken {
|
||||
final SplayTreeMap<String, String> _header =
|
||||
new SplayTreeMap.from({"alg": "HS256", "typ": "JWT"});
|
||||
SplayTreeMap.from({"alg": "HS256", "typ": "JWT"});
|
||||
|
||||
String ipAddress;
|
||||
DateTime issuedAt;
|
||||
|
@ -40,17 +40,17 @@ class AuthToken {
|
|||
this.userId,
|
||||
DateTime issuedAt,
|
||||
Map payload = const {}}) {
|
||||
this.issuedAt = issuedAt ?? new DateTime.now();
|
||||
this.issuedAt = issuedAt ?? DateTime.now();
|
||||
this.payload.addAll(
|
||||
payload?.keys?.fold({}, (out, k) => out..[k.toString()] = payload[k]) ??
|
||||
{});
|
||||
}
|
||||
|
||||
factory AuthToken.fromJson(String jsons) =>
|
||||
new AuthToken.fromMap(json.decode(jsons) as Map);
|
||||
AuthToken.fromMap(json.decode(jsons) as Map);
|
||||
|
||||
factory AuthToken.fromMap(Map data) {
|
||||
return new AuthToken(
|
||||
return AuthToken(
|
||||
ipAddress: data["aud"].toString(),
|
||||
lifeSpan: data["exp"] as num,
|
||||
issuedAt: DateTime.parse(data["iat"].toString()),
|
||||
|
@ -62,17 +62,17 @@ class AuthToken {
|
|||
var split = jwt.split(".");
|
||||
|
||||
if (split.length != 3)
|
||||
throw new AngelHttpException.notAuthenticated(message: "Invalid JWT.");
|
||||
throw AngelHttpException.notAuthenticated(message: "Invalid JWT.");
|
||||
|
||||
var payloadString = decodeBase64(split[1]);
|
||||
return new AuthToken.fromMap(json.decode(payloadString) as Map);
|
||||
return AuthToken.fromMap(json.decode(payloadString) as Map);
|
||||
}
|
||||
|
||||
factory AuthToken.validate(String jwt, Hmac hmac) {
|
||||
var split = jwt.split(".");
|
||||
|
||||
if (split.length != 3)
|
||||
throw new AngelHttpException.notAuthenticated(message: "Invalid JWT.");
|
||||
throw AngelHttpException.notAuthenticated(message: "Invalid JWT.");
|
||||
|
||||
// var headerString = decodeBase64(split[0]);
|
||||
var payloadString = decodeBase64(split[1]);
|
||||
|
@ -80,10 +80,10 @@ class AuthToken {
|
|||
var signature = base64Url.encode(hmac.convert(data.codeUnits).bytes);
|
||||
|
||||
if (signature != split[2])
|
||||
throw new AngelHttpException.notAuthenticated(
|
||||
throw AngelHttpException.notAuthenticated(
|
||||
message: "JWT payload does not match hashed version.");
|
||||
|
||||
return new AuthToken.fromMap(json.decode(payloadString) as Map);
|
||||
return AuthToken.fromMap(json.decode(payloadString) as Map);
|
||||
}
|
||||
|
||||
String serialize(Hmac hmac) {
|
||||
|
@ -111,7 +111,7 @@ SplayTreeMap _splayify(Map map) {
|
|||
map.forEach((k, v) {
|
||||
data[k] = _splay(v);
|
||||
});
|
||||
return new SplayTreeMap.from(data);
|
||||
return SplayTreeMap.from(data);
|
||||
}
|
||||
|
||||
_splay(value) {
|
||||
|
|
|
@ -20,9 +20,9 @@ class ExternalAuthOptions {
|
|||
ExternalAuthOptions._(
|
||||
this.clientId, this.clientSecret, this.redirectUri, this.scopes) {
|
||||
if (clientId == null) {
|
||||
throw new ArgumentError.notNull('clientId');
|
||||
throw ArgumentError.notNull('clientId');
|
||||
} else if (clientSecret == null) {
|
||||
throw new ArgumentError.notNull('clientSecret');
|
||||
throw ArgumentError.notNull('clientSecret');
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -32,13 +32,13 @@ class ExternalAuthOptions {
|
|||
@required redirectUri,
|
||||
Iterable<String> scopes = const []}) {
|
||||
if (redirectUri is String) {
|
||||
return new ExternalAuthOptions._(
|
||||
return ExternalAuthOptions._(
|
||||
clientId, clientSecret, Uri.parse(redirectUri), scopes.toSet());
|
||||
} else if (redirectUri is Uri) {
|
||||
return new ExternalAuthOptions._(
|
||||
return ExternalAuthOptions._(
|
||||
clientId, clientSecret, redirectUri, scopes.toSet());
|
||||
} else {
|
||||
throw new ArgumentError.value(
|
||||
throw ArgumentError.value(
|
||||
redirectUri, 'redirectUri', 'must be a String or Uri');
|
||||
}
|
||||
}
|
||||
|
@ -50,7 +50,7 @@ class ExternalAuthOptions {
|
|||
/// * `client_secret`
|
||||
/// * `redirect_uri`
|
||||
factory ExternalAuthOptions.fromMap(Map map) {
|
||||
return new ExternalAuthOptions(
|
||||
return ExternalAuthOptions(
|
||||
clientId: map['client_id'] as String,
|
||||
clientSecret: map['client_secret'] as String,
|
||||
redirectUri: map['redirect_uri'],
|
||||
|
@ -77,7 +77,7 @@ class ExternalAuthOptions {
|
|||
String clientSecret,
|
||||
redirectUri,
|
||||
Iterable<String> scopes}) {
|
||||
return new ExternalAuthOptions(
|
||||
return ExternalAuthOptions(
|
||||
clientId: clientId ?? this.clientId,
|
||||
clientSecret: clientSecret ?? this.clientSecret,
|
||||
redirectUri: redirectUri ?? this.redirectUri,
|
||||
|
@ -118,11 +118,11 @@ class ExternalAuthOptions {
|
|||
secret = clientSecret;
|
||||
} else {
|
||||
var codeUnits =
|
||||
new List<int>.filled(asteriskCount ?? clientSecret.length, $asterisk);
|
||||
secret = new String.fromCharCodes(codeUnits);
|
||||
List<int>.filled(asteriskCount ?? clientSecret.length, $asterisk);
|
||||
secret = String.fromCharCodes(codeUnits);
|
||||
}
|
||||
|
||||
var b = new StringBuffer('ExternalAuthOptions(');
|
||||
var b = StringBuffer('ExternalAuthOptions(');
|
||||
b.write('clientId=$clientId');
|
||||
b.write(', clientSecret=$secret');
|
||||
b.write(', redirectUri=$redirectUri');
|
||||
|
|
|
@ -7,7 +7,7 @@ RequestHandler forceBasicAuth<User>({String realm}) {
|
|||
return (RequestContext req, ResponseContext res) async {
|
||||
if (req.container.has<User>()) return true;
|
||||
res.headers['www-authenticate'] = 'Basic realm="${realm ?? 'angel_auth'}"';
|
||||
throw new AngelHttpException.notAuthenticated();
|
||||
throw AngelHttpException.notAuthenticated();
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -18,7 +18,7 @@ RequestHandler requireAuthentication<User>() {
|
|||
bool _reject(ResponseContext res) {
|
||||
if (throwError) {
|
||||
res.statusCode = 403;
|
||||
throw new AngelHttpException.forbidden();
|
||||
throw AngelHttpException.forbidden();
|
||||
} else
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -11,10 +11,10 @@ import 'strategy.dart';
|
|||
class AngelAuth<User> {
|
||||
Hmac _hs256;
|
||||
int _jwtLifeSpan;
|
||||
final StreamController<User> _onLogin = new StreamController<User>(),
|
||||
_onLogout = new StreamController<User>();
|
||||
Math.Random _random = new Math.Random.secure();
|
||||
final RegExp _rgxBearer = new RegExp(r"^Bearer");
|
||||
final StreamController<User> _onLogin = StreamController<User>(),
|
||||
_onLogout = StreamController<User>();
|
||||
Math.Random _random = Math.Random.secure();
|
||||
final RegExp _rgxBearer = RegExp(r"^Bearer");
|
||||
|
||||
/// If `true` (default), then JWT's will be stored and retrieved from a `token` cookie.
|
||||
final bool allowCookie;
|
||||
|
@ -68,7 +68,7 @@ class AngelAuth<User> {
|
|||
"ABCDEFHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_"}) {
|
||||
var chars = <int>[];
|
||||
while (chars.length < length) chars.add(_random.nextInt(validChars.length));
|
||||
return new String.fromCharCodes(chars);
|
||||
return String.fromCharCodes(chars);
|
||||
}
|
||||
|
||||
/// `jwtLifeSpan` - should be in *milliseconds*.
|
||||
|
@ -85,16 +85,16 @@ class AngelAuth<User> {
|
|||
this.secureCookies = true,
|
||||
this.reviveTokenEndpoint = "/auth/token"})
|
||||
: super() {
|
||||
_hs256 = new Hmac(sha256, (jwtKey ?? _randomString()).codeUnits);
|
||||
_hs256 = Hmac(sha256, (jwtKey ?? _randomString()).codeUnits);
|
||||
_jwtLifeSpan = jwtLifeSpan?.toInt() ?? -1;
|
||||
}
|
||||
|
||||
Future configureServer(Angel app) async {
|
||||
if (serializer == null)
|
||||
throw new StateError(
|
||||
throw StateError(
|
||||
'An `AngelAuth` plug-in was called without its `serializer` being set. All authentication will fail.');
|
||||
if (deserializer == null)
|
||||
throw new StateError(
|
||||
throw StateError(
|
||||
'An `AngelAuth` plug-in was called without its `deserializer` being set. All authentication will fail.');
|
||||
|
||||
app.container.registerSingleton(this);
|
||||
|
@ -132,20 +132,20 @@ class AngelAuth<User> {
|
|||
String jwt = getJwt(req);
|
||||
|
||||
if (jwt != null) {
|
||||
var token = new AuthToken.validate(jwt, _hs256);
|
||||
var token = AuthToken.validate(jwt, _hs256);
|
||||
|
||||
if (enforceIp) {
|
||||
if (req.ip != null && req.ip != token.ipAddress)
|
||||
throw new AngelHttpException.forbidden(
|
||||
throw AngelHttpException.forbidden(
|
||||
message: "JWT cannot be accessed from this IP address.");
|
||||
}
|
||||
|
||||
if (token.lifeSpan > -1) {
|
||||
var expiry = token.issuedAt
|
||||
.add(new Duration(milliseconds: token.lifeSpan.toInt()));
|
||||
var expiry =
|
||||
token.issuedAt.add(Duration(milliseconds: token.lifeSpan.toInt()));
|
||||
|
||||
if (!expiry.isAfter(new DateTime.now()))
|
||||
throw new AngelHttpException.forbidden(message: "Expired JWT.");
|
||||
if (!expiry.isAfter(DateTime.now()))
|
||||
throw AngelHttpException.forbidden(message: "Expired JWT.");
|
||||
}
|
||||
|
||||
final user = await deserializer(token.userId);
|
||||
|
@ -176,7 +176,7 @@ class AngelAuth<User> {
|
|||
|
||||
void _addProtectedCookie(ResponseContext res, String name, String value) {
|
||||
if (!res.cookies.any((c) => c.name == name)) {
|
||||
res.cookies.add(protectCookie(new Cookie(name, value)));
|
||||
res.cookies.add(protectCookie(Cookie(name, value)));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -190,7 +190,7 @@ class AngelAuth<User> {
|
|||
if (_jwtLifeSpan > 0) {
|
||||
cookie.maxAge ??= _jwtLifeSpan < 0 ? -1 : _jwtLifeSpan ~/ 1000;
|
||||
cookie.expires ??=
|
||||
new DateTime.now().add(new Duration(milliseconds: _jwtLifeSpan));
|
||||
DateTime.now().add(Duration(milliseconds: _jwtLifeSpan));
|
||||
}
|
||||
|
||||
cookie.domain ??= cookieDomain;
|
||||
|
@ -209,24 +209,24 @@ class AngelAuth<User> {
|
|||
jwt = body['token']?.toString();
|
||||
}
|
||||
if (jwt == null) {
|
||||
throw new AngelHttpException.forbidden(message: "No JWT provided");
|
||||
throw AngelHttpException.forbidden(message: "No JWT provided");
|
||||
} else {
|
||||
var token = new AuthToken.validate(jwt, _hs256);
|
||||
var token = AuthToken.validate(jwt, _hs256);
|
||||
if (enforceIp) {
|
||||
if (req.ip != token.ipAddress)
|
||||
throw new AngelHttpException.forbidden(
|
||||
throw AngelHttpException.forbidden(
|
||||
message: "JWT cannot be accessed from this IP address.");
|
||||
}
|
||||
|
||||
if (token.lifeSpan > -1) {
|
||||
var expiry = token.issuedAt
|
||||
.add(new Duration(milliseconds: token.lifeSpan.toInt()));
|
||||
.add(Duration(milliseconds: token.lifeSpan.toInt()));
|
||||
|
||||
if (!expiry.isAfter(new DateTime.now())) {
|
||||
if (!expiry.isAfter(DateTime.now())) {
|
||||
//print(
|
||||
// 'Token has indeed expired! Resetting assignment date to current timestamp...');
|
||||
// Extend its lifespan by changing iat
|
||||
token.issuedAt = new DateTime.now();
|
||||
token.issuedAt = DateTime.now();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -239,7 +239,7 @@ class AngelAuth<User> {
|
|||
}
|
||||
} catch (e) {
|
||||
if (e is AngelHttpException) rethrow;
|
||||
throw new AngelHttpException.badRequest(message: "Malformed JWT");
|
||||
throw AngelHttpException.badRequest(message: "Malformed JWT");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -254,7 +254,9 @@ class AngelAuth<User> {
|
|||
RequestHandler authenticate(type, [AngelAuthOptions<User> options]) {
|
||||
return (RequestContext req, ResponseContext res) async {
|
||||
List<String> names = [];
|
||||
var arr = type is Iterable ? type.toList() : [type];
|
||||
var arr = type is Iterable
|
||||
? type.map((x) => x.toString()).toList()
|
||||
: [type.toString()];
|
||||
|
||||
for (String t in arr) {
|
||||
var n = t
|
||||
|
@ -269,7 +271,7 @@ class AngelAuth<User> {
|
|||
var name = names[i];
|
||||
|
||||
var strategy = strategies[name] ??=
|
||||
throw new ArgumentError('No strategy "$name" found.');
|
||||
throw ArgumentError('No strategy "$name" found.');
|
||||
|
||||
var hasExisting = req.container.has<User>();
|
||||
var result = hasExisting
|
||||
|
@ -281,7 +283,7 @@ class AngelAuth<User> {
|
|||
var userId = await serializer(result);
|
||||
|
||||
// Create JWT
|
||||
var token = new AuthToken(
|
||||
var token = AuthToken(
|
||||
userId: userId, lifeSpan: _jwtLifeSpan, ipAddress: req.ip);
|
||||
var jwt = token.serialize(_hs256);
|
||||
|
||||
|
@ -306,7 +308,7 @@ class AngelAuth<User> {
|
|||
}
|
||||
|
||||
if (options?.successRedirect?.isNotEmpty == true) {
|
||||
res.redirect(options.successRedirect);
|
||||
await res.redirect(options.successRedirect);
|
||||
return false;
|
||||
} else if (options?.canRespondWithJson != false &&
|
||||
req.accepts('application/json')) {
|
||||
|
@ -326,10 +328,10 @@ class AngelAuth<User> {
|
|||
res.headers.containsKey('location'))
|
||||
return false;
|
||||
else if (options?.failureRedirect != null) {
|
||||
res.redirect(options.failureRedirect);
|
||||
await res.redirect(options.failureRedirect);
|
||||
return false;
|
||||
} else
|
||||
throw new AngelHttpException.notAuthenticated();
|
||||
throw AngelHttpException.notAuthenticated();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -349,8 +351,8 @@ class AngelAuth<User> {
|
|||
/// Log a user in on-demand.
|
||||
Future loginById(userId, RequestContext req, ResponseContext res) async {
|
||||
var user = await deserializer(userId);
|
||||
var token = new AuthToken(
|
||||
userId: userId, lifeSpan: _jwtLifeSpan, ipAddress: req.ip);
|
||||
var token =
|
||||
AuthToken(userId: userId, lifeSpan: _jwtLifeSpan, ipAddress: req.ip);
|
||||
_apply(req, res, token, user);
|
||||
_onLogin.add(user);
|
||||
|
||||
|
@ -375,7 +377,7 @@ class AngelAuth<User> {
|
|||
if (options != null &&
|
||||
options.successRedirect != null &&
|
||||
options.successRedirect.isNotEmpty) {
|
||||
res.redirect(options.successRedirect);
|
||||
await res.redirect(options.successRedirect);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
|
@ -10,7 +10,7 @@ AngelAuthCallback confirmPopupAuthentication({String eventName = 'token'}) {
|
|||
var detail = json.encode({'detail': jwt});
|
||||
|
||||
res
|
||||
..contentType = new MediaType('text', 'html')
|
||||
..contentType = MediaType('text', 'html')
|
||||
..write('''
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
@ -18,7 +18,7 @@ AngelAuthCallback confirmPopupAuthentication({String eventName = 'token'}) {
|
|||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Authentication Success</title>
|
||||
<script>
|
||||
var ev = new CustomEvent($evt, $detail);
|
||||
var ev = CustomEvent($evt, $detail);
|
||||
window.opener.dispatchEvent(ev);
|
||||
window.close();
|
||||
</script>
|
||||
|
|
|
@ -11,8 +11,8 @@ typedef FutureOr<User> LocalAuthVerifier<User>(
|
|||
String username, String password);
|
||||
|
||||
class LocalAuthStrategy<User> extends AuthStrategy<User> {
|
||||
RegExp _rgxBasic = new RegExp(r'^Basic (.+)$', caseSensitive: false);
|
||||
RegExp _rgxUsrPass = new RegExp(r'^([^:]+):(.+)$');
|
||||
RegExp _rgxBasic = RegExp(r'^Basic (.+)$', caseSensitive: false);
|
||||
RegExp _rgxUsrPass = RegExp(r'^([^:]+):(.+)$');
|
||||
|
||||
LocalAuthVerifier<User> verifier;
|
||||
String usernameField;
|
||||
|
@ -34,7 +34,7 @@ class LocalAuthStrategy<User> extends AuthStrategy<User> {
|
|||
@override
|
||||
Future<User> authenticate(RequestContext req, ResponseContext res,
|
||||
[AngelAuthOptions options_]) async {
|
||||
AngelAuthOptions options = options_ ?? new AngelAuthOptions();
|
||||
AngelAuthOptions options = options_ ?? AngelAuthOptions();
|
||||
User verificationResult;
|
||||
|
||||
if (allowBasic) {
|
||||
|
@ -43,13 +43,13 @@ class LocalAuthStrategy<User> extends AuthStrategy<User> {
|
|||
if (_rgxBasic.hasMatch(authHeader)) {
|
||||
String base64AuthString = _rgxBasic.firstMatch(authHeader).group(1);
|
||||
String authString =
|
||||
new String.fromCharCodes(base64.decode(base64AuthString));
|
||||
String.fromCharCodes(base64.decode(base64AuthString));
|
||||
if (_rgxUsrPass.hasMatch(authString)) {
|
||||
Match usrPassMatch = _rgxUsrPass.firstMatch(authString);
|
||||
verificationResult =
|
||||
await verifier(usrPassMatch.group(1), usrPassMatch.group(2));
|
||||
} else
|
||||
throw new AngelHttpException.badRequest(errors: [invalidMessage]);
|
||||
throw AngelHttpException.badRequest(errors: [invalidMessage]);
|
||||
|
||||
if (verificationResult == false || verificationResult == null) {
|
||||
res
|
||||
|
@ -78,20 +78,20 @@ class LocalAuthStrategy<User> extends AuthStrategy<User> {
|
|||
if (verificationResult == false || verificationResult == null) {
|
||||
if (options.failureRedirect != null &&
|
||||
options.failureRedirect.isNotEmpty) {
|
||||
res.redirect(options.failureRedirect, code: 401);
|
||||
await res.redirect(options.failureRedirect, code: 401);
|
||||
return null;
|
||||
}
|
||||
|
||||
if (forceBasic) {
|
||||
res.headers['www-authenticate'] = 'Basic realm="$realm"';
|
||||
throw new AngelHttpException.notAuthenticated();
|
||||
throw AngelHttpException.notAuthenticated();
|
||||
}
|
||||
|
||||
return null;
|
||||
} else if (verificationResult != null && verificationResult != false) {
|
||||
return verificationResult;
|
||||
} else {
|
||||
throw new AngelHttpException.notAuthenticated();
|
||||
throw AngelHttpException.notAuthenticated();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
name: angel_auth
|
||||
description: A complete authentication plugin for Angel. Includes support for stateless JWT tokens, Basic Auth, and more.
|
||||
version: 2.1.2
|
||||
version: 2.1.3
|
||||
author: Tobe O <thosakwe@gmail.com>
|
||||
homepage: https://github.com/angel-dart/angel_auth
|
||||
environment:
|
||||
sdk: ">=2.0.0-dev <3.0.0"
|
||||
dependencies:
|
||||
angel_framework: ^2.0.0-alpha
|
||||
angel_framework: ^2.0.0-rc.6
|
||||
charcode: ^1.0.0
|
||||
collection: ^1.0.0
|
||||
crypto: ^2.0.0
|
||||
|
|
|
@ -3,22 +3,21 @@ import "package:crypto/crypto.dart";
|
|||
import "package:test/test.dart";
|
||||
|
||||
main() async {
|
||||
final Hmac hmac = new Hmac(sha256, "angel_auth".codeUnits);
|
||||
final Hmac hmac = Hmac(sha256, "angel_auth".codeUnits);
|
||||
|
||||
test("sample serialization", () {
|
||||
var token = new AuthToken(ipAddress: "localhost", userId: "thosakwe");
|
||||
var token = AuthToken(ipAddress: "localhost", userId: "thosakwe");
|
||||
var jwt = token.serialize(hmac);
|
||||
print(jwt);
|
||||
|
||||
var parsed = new AuthToken.validate(jwt, hmac);
|
||||
var parsed = AuthToken.validate(jwt, hmac);
|
||||
print(parsed.toJson());
|
||||
expect(parsed.toJson()['aud'], equals(token.ipAddress));
|
||||
expect(parsed.toJson()['sub'], equals(token.userId));
|
||||
});
|
||||
|
||||
test('custom payload', () {
|
||||
var token =
|
||||
new AuthToken(ipAddress: "localhost", userId: "thosakwe", payload: {
|
||||
var token = AuthToken(ipAddress: "localhost", userId: "thosakwe", payload: {
|
||||
"foo": "bar",
|
||||
"baz": {
|
||||
"one": 1,
|
||||
|
@ -28,7 +27,7 @@ main() async {
|
|||
var jwt = token.serialize(hmac);
|
||||
print(jwt);
|
||||
|
||||
var parsed = new AuthToken.validate(jwt, hmac);
|
||||
var parsed = AuthToken.validate(jwt, hmac);
|
||||
print(parsed.toJson());
|
||||
expect(parsed.toJson()['pld'], equals(token.payload));
|
||||
});
|
||||
|
|
|
@ -14,7 +14,7 @@ class User extends Model {
|
|||
User({this.username, this.password});
|
||||
|
||||
static User parse(Map map) {
|
||||
return new User(
|
||||
return User(
|
||||
username: map['username'] as String,
|
||||
password: map['password'] as String,
|
||||
);
|
||||
|
@ -41,9 +41,9 @@ main() {
|
|||
|
||||
setUp(() async {
|
||||
hierarchicalLoggingEnabled = true;
|
||||
app = new Angel();
|
||||
angelHttp = new AngelHttp(app);
|
||||
app.use('/users', new MapService());
|
||||
app = Angel();
|
||||
angelHttp = AngelHttp(app);
|
||||
app.use('/users', MapService());
|
||||
|
||||
var oldErrorHandler = app.errorHandler;
|
||||
app.errorHandler = (e, req, res) {
|
||||
|
@ -51,7 +51,7 @@ main() {
|
|||
return oldErrorHandler(e, req, res);
|
||||
};
|
||||
|
||||
app.logger = new Logger('angel_auth')
|
||||
app.logger = Logger('angel_auth')
|
||||
..level = Level.FINEST
|
||||
..onRecord.listen((rec) {
|
||||
print(rec);
|
||||
|
@ -69,7 +69,7 @@ main() {
|
|||
.findService('users')
|
||||
.create({'username': 'jdoe1', 'password': 'password'});
|
||||
|
||||
auth = new AngelAuth<User>();
|
||||
auth = AngelAuth<User>();
|
||||
auth.serializer = (u) => u.id;
|
||||
auth.deserializer =
|
||||
(id) async => await app.findService('users').read(id) as User;
|
||||
|
@ -77,8 +77,7 @@ main() {
|
|||
await app.configure(auth.configureServer);
|
||||
app.fallback(auth.decodeJwt);
|
||||
|
||||
auth.strategies['local'] =
|
||||
new LocalAuthStrategy((username, password) async {
|
||||
auth.strategies['local'] = LocalAuthStrategy((username, password) async {
|
||||
var users = await app
|
||||
.findService('users')
|
||||
.index()
|
||||
|
@ -91,7 +90,7 @@ main() {
|
|||
app.post(
|
||||
'/login',
|
||||
auth.authenticate('local',
|
||||
new AngelAuthOptions(callback: (req, res, token) {
|
||||
AngelAuthOptions(callback: (req, res, token) {
|
||||
res
|
||||
..write('Hello!')
|
||||
..close();
|
||||
|
@ -101,7 +100,7 @@ main() {
|
|||
(req, res) {
|
||||
if (!req.container.has<User>()) {
|
||||
req.container.registerSingleton<User>(
|
||||
new User(username: req.params['name']?.toString()));
|
||||
User(username: req.params['name']?.toString()));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -110,7 +109,7 @@ main() {
|
|||
auth.authenticate('local'),
|
||||
);
|
||||
|
||||
client = new http.Client();
|
||||
client = http.Client();
|
||||
server = await angelHttp.startServer();
|
||||
url = 'http://${server.address.address}:${server.port}';
|
||||
});
|
||||
|
|
|
@ -2,7 +2,7 @@ import 'package:angel_auth/angel_auth.dart';
|
|||
import 'package:test/test.dart';
|
||||
|
||||
void main() {
|
||||
var options = new ExternalAuthOptions(
|
||||
var options = ExternalAuthOptions(
|
||||
clientId: 'foo',
|
||||
clientSecret: 'bar',
|
||||
redirectUri: 'http://example.com',
|
||||
|
@ -25,7 +25,7 @@ void main() {
|
|||
redirectUri: 'https://yes.no',
|
||||
scopes: ['a', 'b'],
|
||||
),
|
||||
new ExternalAuthOptions(
|
||||
ExternalAuthOptions(
|
||||
clientId: 'hey',
|
||||
clientSecret: 'hello',
|
||||
redirectUri: 'https://yes.no',
|
||||
|
@ -42,7 +42,7 @@ void main() {
|
|||
group('new()', () {
|
||||
test('accepts uri', () {
|
||||
expect(
|
||||
new ExternalAuthOptions(
|
||||
ExternalAuthOptions(
|
||||
clientId: 'foo',
|
||||
clientSecret: 'bar',
|
||||
redirectUri: Uri.parse('http://example.com'),
|
||||
|
@ -53,7 +53,7 @@ void main() {
|
|||
|
||||
test('accepts string', () {
|
||||
expect(
|
||||
new ExternalAuthOptions(
|
||||
ExternalAuthOptions(
|
||||
clientId: 'foo',
|
||||
clientSecret: 'bar',
|
||||
redirectUri: 'http://example.com',
|
||||
|
@ -64,7 +64,7 @@ void main() {
|
|||
|
||||
test('rejects invalid redirectUri', () {
|
||||
expect(
|
||||
() => new ExternalAuthOptions(
|
||||
() => ExternalAuthOptions(
|
||||
clientId: 'foo', clientSecret: 'bar', redirectUri: 24.5),
|
||||
throwsArgumentError,
|
||||
);
|
||||
|
@ -72,7 +72,7 @@ void main() {
|
|||
|
||||
test('ensures id not null', () {
|
||||
expect(
|
||||
() => new ExternalAuthOptions(
|
||||
() => ExternalAuthOptions(
|
||||
clientId: null,
|
||||
clientSecret: 'bar',
|
||||
redirectUri: 'http://example.com'),
|
||||
|
@ -82,7 +82,7 @@ void main() {
|
|||
|
||||
test('ensures secret not null', () {
|
||||
expect(
|
||||
() => new ExternalAuthOptions(
|
||||
() => ExternalAuthOptions(
|
||||
clientId: 'foo',
|
||||
clientSecret: null,
|
||||
redirectUri: 'http://example.com'),
|
||||
|
@ -94,14 +94,14 @@ void main() {
|
|||
group('fromMap()', () {
|
||||
test('rejects invalid map', () {
|
||||
expect(
|
||||
() => new ExternalAuthOptions.fromMap({'yes': 'no'}),
|
||||
() => ExternalAuthOptions.fromMap({'yes': 'no'}),
|
||||
throwsArgumentError,
|
||||
);
|
||||
});
|
||||
|
||||
test('accepts correct map', () {
|
||||
expect(
|
||||
new ExternalAuthOptions.fromMap({
|
||||
ExternalAuthOptions.fromMap({
|
||||
'client_id': 'foo',
|
||||
'client_secret': 'bar',
|
||||
'redirect_uri': 'http://example.com',
|
||||
|
|
|
@ -8,10 +8,9 @@ import 'package:http/http.dart' as http;
|
|||
import 'package:logging/logging.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
final AngelAuth<Map<String, String>> auth =
|
||||
new AngelAuth<Map<String, String>>();
|
||||
final AngelAuth<Map<String, String>> auth = AngelAuth<Map<String, String>>();
|
||||
var headers = <String, String>{'accept': 'application/json'};
|
||||
var localOpts = new AngelAuthOptions<Map<String, String>>(
|
||||
var localOpts = AngelAuthOptions<Map<String, String>>(
|
||||
failureRedirect: '/failure', successRedirect: '/success');
|
||||
Map<String, String> sampleUser = {'hello': 'world'};
|
||||
|
||||
|
@ -26,7 +25,7 @@ Future wireAuth(Angel app) async {
|
|||
auth.serializer = (user) async => 1337;
|
||||
auth.deserializer = (id) async => sampleUser;
|
||||
|
||||
auth.strategies['local'] = new LocalAuthStrategy(verifier);
|
||||
auth.strategies['local'] = LocalAuthStrategy(verifier);
|
||||
await app.configure(auth.configureServer);
|
||||
app.fallback(auth.decodeJwt);
|
||||
}
|
||||
|
@ -39,9 +38,9 @@ main() async {
|
|||
String basicAuthUrl;
|
||||
|
||||
setUp(() async {
|
||||
client = new http.Client();
|
||||
app = new Angel();
|
||||
angelHttp = new AngelHttp(app, useZone: false);
|
||||
client = http.Client();
|
||||
app = Angel();
|
||||
angelHttp = AngelHttp(app, useZone: false);
|
||||
await app.configure(wireAuth);
|
||||
app.get('/hello', (req, res) => 'Woo auth',
|
||||
middleware: [auth.authenticate('local')]);
|
||||
|
@ -52,7 +51,7 @@ main() async {
|
|||
]);
|
||||
app.get('/failure', (req, res) => "nope");
|
||||
|
||||
app.logger = new Logger('angel_auth')
|
||||
app.logger = Logger('angel_auth')
|
||||
..onRecord.listen((rec) {
|
||||
if (rec.error != null) {
|
||||
print(rec.error);
|
||||
|
@ -114,7 +113,7 @@ main() async {
|
|||
test('force basic', () async {
|
||||
auth.strategies.clear();
|
||||
auth.strategies['local'] =
|
||||
new LocalAuthStrategy(verifier, forceBasic: true, realm: 'test');
|
||||
LocalAuthStrategy(verifier, forceBasic: true, realm: 'test');
|
||||
var response = await client.get("$url/hello", headers: {
|
||||
'accept': 'application/json',
|
||||
'content-type': 'application/json'
|
||||
|
|
|
@ -7,20 +7,20 @@ const Duration threeDays = const Duration(days: 3);
|
|||
|
||||
void main() {
|
||||
Cookie defaultCookie;
|
||||
var auth = new AngelAuth(
|
||||
var auth = AngelAuth(
|
||||
secureCookies: true,
|
||||
cookieDomain: 'SECURE',
|
||||
jwtLifeSpan: threeDays.inMilliseconds,
|
||||
);
|
||||
|
||||
setUp(() => defaultCookie = new Cookie('a', 'b'));
|
||||
setUp(() => defaultCookie = Cookie('a', 'b'));
|
||||
|
||||
test('sets maxAge', () {
|
||||
expect(auth.protectCookie(defaultCookie).maxAge, threeDays.inSeconds);
|
||||
});
|
||||
|
||||
test('sets expires', () {
|
||||
var now = new DateTime.now();
|
||||
var now = DateTime.now();
|
||||
var expiry = auth.protectCookie(defaultCookie).expires;
|
||||
var diff = expiry.difference(now);
|
||||
expect(diff.inSeconds, threeDays.inSeconds);
|
||||
|
|
Loading…
Reference in a new issue