diff --git a/.dart_tool/pub/bin/sdk-version b/.dart_tool/pub/bin/sdk-version new file mode 100644 index 00000000..729c9a1d --- /dev/null +++ b/.dart_tool/pub/bin/sdk-version @@ -0,0 +1 @@ +2.0.0-dev.68.0 diff --git a/.dart_tool/pub/bin/test/test.dart.snapshot.dart2 b/.dart_tool/pub/bin/test/test.dart.snapshot.dart2 new file mode 100644 index 00000000..aacaf144 Binary files /dev/null and b/.dart_tool/pub/bin/test/test.dart.snapshot.dart2 differ diff --git a/CHANGELOG.md b/CHANGELOG.md index d8de60c3..8cd4e617 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +# 1.2.0 +* Deprecate `requireAuth`, in favor of `requireAuthentication`. +* Allow configuring of the `userKey`. +* Add `authenticateAndContinue`. +* Deprecate `middlewareName`. + # 1.1.1+6 * Fix a small logic bug that prevented `LocalAuthStrategy` from correctly propagating the authenticated user when diff --git a/lib/auth_token.dart b/lib/auth_token.dart index 8273e533..ff19d35e 100644 --- a/lib/auth_token.dart +++ b/lib/auth_token.dart @@ -1,4 +1,4 @@ /// Stand-alone JWT library. library angel_auth.auth_token; -export 'src/auth_token.dart'; \ No newline at end of file +export 'src/auth_token.dart'; diff --git a/lib/src/defs.dart b/lib/src/defs.dart index 3b246922..c7538c9e 100644 --- a/lib/src/defs.dart +++ b/lib/src/defs.dart @@ -4,4 +4,4 @@ import 'dart:async'; typedef FutureOr UserSerializer(T user); /// Deserializes a user from the session. -typedef FutureOr UserDeserializer(userId); \ No newline at end of file +typedef FutureOr UserDeserializer(userId); diff --git a/lib/src/middleware/require_auth.dart b/lib/src/middleware/require_auth.dart index c4a2bcf2..b739d1e9 100644 --- a/lib/src/middleware/require_auth.dart +++ b/lib/src/middleware/require_auth.dart @@ -1,5 +1,3 @@ -import 'dart:async'; -import 'dart:io'; import 'package:angel_framework/angel_framework.dart'; /// Forces Basic authentication over the requested resource, with the given [realm] name, if no JWT is present. @@ -10,27 +8,32 @@ RequestHandler forceBasicAuth({String realm}) { if (req.properties.containsKey('user')) return true; res - ..statusCode = HttpStatus.UNAUTHORIZED - ..headers[HttpHeaders.WWW_AUTHENTICATE] = - 'Basic realm="${realm ?? 'angel_auth'}"' + ..statusCode = 401 + ..headers['www-authenticate'] = 'Basic realm="${realm ?? 'angel_auth'}"' ..end(); return false; }; } -/// Restricts access to a resource via authentication. -Future requireAuth(RequestContext req, ResponseContext res, - {bool throwError: true}) async { - bool _reject(ResponseContext res) { - if (throwError) { - res.statusCode = HttpStatus.FORBIDDEN; - throw new AngelHttpException.forbidden(); - } else - return false; - } +/// Use [requireAuthentication] instead. +@deprecated +final RequestMiddleware requireAuth = requireAuthentication(userKey: 'user'); - if (req.properties.containsKey('user') || req.method == 'OPTIONS') - return true; - else - return _reject(res); +/// Restricts access to a resource via authentication. +RequestMiddleware requireAuthentication({String userKey: 'user'}) { + return (RequestContext req, ResponseContext res, + {bool throwError: true}) async { + bool _reject(ResponseContext res) { + if (throwError) { + res.statusCode = 403; + throw new AngelHttpException.forbidden(); + } else + return false; + } + + if (req.properties.containsKey(userKey) || req.method == 'OPTIONS') + return true; + else + return _reject(res); + }; } diff --git a/lib/src/plugin.dart b/lib/src/plugin.dart index c25a20bf..5fcd5f98 100644 --- a/lib/src/plugin.dart +++ b/lib/src/plugin.dart @@ -38,7 +38,8 @@ class AngelAuth { /// Only applies if [allowCookie] is `true`. final String cookiePath; - /// The name to register [requireAuth] as. Default: `auth`. + /// The name to register [requireAuthentication] as. Default: `auth`. + @deprecated String middlewareName; /// If `true` (default), then JWT's will be considered invalid if used from a different IP than the first user's it was issued to. @@ -104,7 +105,8 @@ class AngelAuth { app.container.singleton(this); if (runtimeType != AngelAuth) app.container.singleton(this, as: AngelAuth); - app.registerMiddleware(middlewareName, requireAuth); + // ignore: deprecated_member_use + app.registerMiddleware(middlewareName, requireAuthentication()); if (reviveTokenEndpoint != null) { app.post(reviveTokenEndpoint, reviveJwt); @@ -189,9 +191,7 @@ class AngelAuth { } if (_jwtLifeSpan > 0) { - cookie.maxAge ??= _jwtLifeSpan < 0 - ? -1 - : _jwtLifeSpan ~/ 1000; + cookie.maxAge ??= _jwtLifeSpan < 0 ? -1 : _jwtLifeSpan ~/ 1000; cookie.expires ??= new DateTime.now().add(new Duration(milliseconds: _jwtLifeSpan)); } @@ -308,7 +308,7 @@ class AngelAuth { } if (options?.successRedirect?.isNotEmpty == true) { - res.redirect(options.successRedirect, code: HttpStatus.OK); + res.redirect(options.successRedirect, code: 200); return false; } else if (options?.canRespondWithJson != false && req.accepts('application/json')) { @@ -325,7 +325,7 @@ class AngelAuth { // Check if not redirect if (res.statusCode == 301 || res.statusCode == 302 || - res.headers.containsKey(HttpHeaders.LOCATION)) + res.headers.containsKey('location')) return false; else throw new AngelHttpException.notAuthenticated(); diff --git a/lib/src/popup_page.dart b/lib/src/popup_page.dart index 0363e522..71a709ab 100644 --- a/lib/src/popup_page.dart +++ b/lib/src/popup_page.dart @@ -6,7 +6,7 @@ import 'options.dart'; AngelAuthCallback confirmPopupAuthentication({String eventName: 'token'}) { return (req, ResponseContext res, String jwt) async { res - ..contentType = ContentType.HTML + ..contentType = new ContentType('text', 'html') ..write(''' diff --git a/lib/src/strategies/local.dart b/lib/src/strategies/local.dart index 9f516025..126d468b 100644 --- a/lib/src/strategies/local.dart +++ b/lib/src/strategies/local.dart @@ -1,6 +1,5 @@ import 'dart:async'; import 'package:dart2_constant/convert.dart'; -import 'dart:io'; import 'package:angel_framework/angel_framework.dart'; import '../options.dart'; import '../strategy.dart'; @@ -45,7 +44,7 @@ class LocalAuthStrategy extends AuthStrategy { var verificationResult; if (allowBasic) { - String authHeader = req.headers.value(HttpHeaders.AUTHORIZATION) ?? ""; + String authHeader = req.headers.value('authorization') ?? ""; if (_rgxBasic.hasMatch(authHeader)) { String base64AuthString = _rgxBasic.firstMatch(authHeader).group(1); @@ -82,14 +81,14 @@ class LocalAuthStrategy extends AuthStrategy { if (verificationResult == false || verificationResult == null) { if (options.failureRedirect != null && options.failureRedirect.isNotEmpty) { - res.redirect(options.failureRedirect, code: HttpStatus.UNAUTHORIZED); + res.redirect(options.failureRedirect, code: 401); return false; } if (forceBasic) { res ..statusCode = 401 - ..headers[HttpHeaders.WWW_AUTHENTICATE] = 'Basic realm="$realm"' + ..headers['www-authenticate'] = 'Basic realm="$realm"' ..end(); } diff --git a/lib/src/strategies/strategies.dart b/lib/src/strategies/strategies.dart index b86a4fdc..ce1589a2 100644 --- a/lib/src/strategies/strategies.dart +++ b/lib/src/strategies/strategies.dart @@ -1 +1 @@ -export 'local.dart'; \ No newline at end of file +export 'local.dart'; diff --git a/lib/src/strategy.dart b/lib/src/strategy.dart index b464f8e1..965fe76c 100644 --- a/lib/src/strategy.dart +++ b/lib/src/strategy.dart @@ -7,8 +7,9 @@ abstract class AuthStrategy { String name; /// Authenticates or rejects an incoming user. - Future authenticate(RequestContext req, ResponseContext res, [AngelAuthOptions options]); + Future authenticate(RequestContext req, ResponseContext res, + [AngelAuthOptions options]); /// Determines whether a signed-in user can log out or not. Future canLogout(RequestContext req, ResponseContext res); -} \ No newline at end of file +} diff --git a/pubspec.yaml b/pubspec.yaml index b9170bba..6a5348b6 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: angel_auth description: A complete authentication plugin for Angel. -version: 1.1.1+6 +version: 1.2.0 author: Tobe O homepage: https://github.com/angel-dart/angel_auth environment: diff --git a/test/local_test.dart b/test/local_test.dart index d8433a03..e6b2ee28 100644 --- a/test/local_test.dart +++ b/test/local_test.dart @@ -7,7 +7,7 @@ import 'package:http/http.dart' as http; import 'package:test/test.dart'; final AngelAuth auth = new AngelAuth(); -var headers = {HttpHeaders.ACCEPT: ContentType.JSON.mimeType}; +var headers = {'accept': 'application/json'}; AngelAuthOptions localOpts = new AngelAuthOptions( failureRedirect: '/failure', successRedirect: '/success'); Map sampleUser = {'hello': 'world'}; @@ -46,8 +46,7 @@ main() async { app.get('/success', "yep", middleware: ['auth']); app.get('/failure', "nope"); - HttpServer server = - await angelHttp.startServer('127.0.0.1', 0); + HttpServer server = await angelHttp.startServer('127.0.0.1', 0); url = "http://${server.address.host}:${server.port}"; basicAuthUrl = "http://username:password@${server.address.host}:${server.port}"; @@ -71,25 +70,25 @@ main() async { Map postData = {'username': 'username', 'password': 'password'}; var response = await client.post("$url/login", body: json.encode(postData), - headers: {HttpHeaders.CONTENT_TYPE: ContentType.JSON.mimeType}); + headers: {'content-type': 'application/json'}); expect(response.statusCode, equals(200)); - expect(response.headers[HttpHeaders.LOCATION], equals('/success')); + expect(response.headers['location'], equals('/success')); }); test('failureRedirect', () async { Map postData = {'username': 'password', 'password': 'username'}; var response = await client.post("$url/login", body: json.encode(postData), - headers: {HttpHeaders.CONTENT_TYPE: ContentType.JSON.mimeType}); + headers: {'content-type': 'application/json'}); print("Login response: ${response.body}"); - expect(response.headers[HttpHeaders.LOCATION], equals('/failure')); + expect(response.headers['location'], equals('/failure')); expect(response.statusCode, equals(401)); }); test('allow basic', () async { String authString = base64.encode("username:password".runes.toList()); - var response = await client.get("$url/hello", - headers: {HttpHeaders.AUTHORIZATION: 'Basic $authString'}); + var response = await client + .get("$url/hello", headers: {'authorization': 'Basic $authString'}); expect(response.body, equals('"Woo auth"')); }); @@ -104,7 +103,6 @@ main() async { .add(new LocalAuthStrategy(verifier, forceBasic: true, realm: 'test')); var response = await client.get("$url/hello", headers: headers); print(response.headers); - expect(response.headers[HttpHeaders.WWW_AUTHENTICATE], - equals('Basic realm="test"')); + expect(response.headers['www-authenticate'], equals('Basic realm="test"')); }); }