requireAuth -> requireAuthentication

This commit is contained in:
Tobe O 2018-07-12 13:11:54 -04:00
parent 9fcfcb6f01
commit f3c5b7988a
13 changed files with 56 additions and 48 deletions

View file

@ -0,0 +1 @@
2.0.0-dev.68.0

Binary file not shown.

View file

@ -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 # 1.1.1+6
* Fix a small logic bug that prevented `LocalAuthStrategy` * Fix a small logic bug that prevented `LocalAuthStrategy`
from correctly propagating the authenticated user when from correctly propagating the authenticated user when

View file

@ -1,5 +1,3 @@
import 'dart:async';
import 'dart:io';
import 'package:angel_framework/angel_framework.dart'; import 'package:angel_framework/angel_framework.dart';
/// Forces Basic authentication over the requested resource, with the given [realm] name, if no JWT is present. /// 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; if (req.properties.containsKey('user')) return true;
res res
..statusCode = HttpStatus.UNAUTHORIZED ..statusCode = 401
..headers[HttpHeaders.WWW_AUTHENTICATE] = ..headers['www-authenticate'] = 'Basic realm="${realm ?? 'angel_auth'}"'
'Basic realm="${realm ?? 'angel_auth'}"'
..end(); ..end();
return false; return false;
}; };
} }
/// Use [requireAuthentication] instead.
@deprecated
final RequestMiddleware requireAuth = requireAuthentication(userKey: 'user');
/// Restricts access to a resource via authentication. /// Restricts access to a resource via authentication.
Future<bool> requireAuth(RequestContext req, ResponseContext res, RequestMiddleware requireAuthentication({String userKey: 'user'}) {
return (RequestContext req, ResponseContext res,
{bool throwError: true}) async { {bool throwError: true}) async {
bool _reject(ResponseContext res) { bool _reject(ResponseContext res) {
if (throwError) { if (throwError) {
res.statusCode = HttpStatus.FORBIDDEN; res.statusCode = 403;
throw new AngelHttpException.forbidden(); throw new AngelHttpException.forbidden();
} else } else
return false; return false;
} }
if (req.properties.containsKey('user') || req.method == 'OPTIONS') if (req.properties.containsKey(userKey) || req.method == 'OPTIONS')
return true; return true;
else else
return _reject(res); return _reject(res);
};
} }

View file

@ -38,7 +38,8 @@ class AngelAuth<T> {
/// Only applies if [allowCookie] is `true`. /// Only applies if [allowCookie] is `true`.
final String cookiePath; final String cookiePath;
/// The name to register [requireAuth] as. Default: `auth`. /// The name to register [requireAuthentication] as. Default: `auth`.
@deprecated
String middlewareName; 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. /// 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<T> {
app.container.singleton(this); app.container.singleton(this);
if (runtimeType != AngelAuth) app.container.singleton(this, as: AngelAuth); if (runtimeType != AngelAuth) app.container.singleton(this, as: AngelAuth);
app.registerMiddleware(middlewareName, requireAuth); // ignore: deprecated_member_use
app.registerMiddleware(middlewareName, requireAuthentication());
if (reviveTokenEndpoint != null) { if (reviveTokenEndpoint != null) {
app.post(reviveTokenEndpoint, reviveJwt); app.post(reviveTokenEndpoint, reviveJwt);
@ -189,9 +191,7 @@ class AngelAuth<T> {
} }
if (_jwtLifeSpan > 0) { if (_jwtLifeSpan > 0) {
cookie.maxAge ??= _jwtLifeSpan < 0 cookie.maxAge ??= _jwtLifeSpan < 0 ? -1 : _jwtLifeSpan ~/ 1000;
? -1
: _jwtLifeSpan ~/ 1000;
cookie.expires ??= cookie.expires ??=
new DateTime.now().add(new Duration(milliseconds: _jwtLifeSpan)); new DateTime.now().add(new Duration(milliseconds: _jwtLifeSpan));
} }
@ -308,7 +308,7 @@ class AngelAuth<T> {
} }
if (options?.successRedirect?.isNotEmpty == true) { if (options?.successRedirect?.isNotEmpty == true) {
res.redirect(options.successRedirect, code: HttpStatus.OK); res.redirect(options.successRedirect, code: 200);
return false; return false;
} else if (options?.canRespondWithJson != false && } else if (options?.canRespondWithJson != false &&
req.accepts('application/json')) { req.accepts('application/json')) {
@ -325,7 +325,7 @@ class AngelAuth<T> {
// Check if not redirect // Check if not redirect
if (res.statusCode == 301 || if (res.statusCode == 301 ||
res.statusCode == 302 || res.statusCode == 302 ||
res.headers.containsKey(HttpHeaders.LOCATION)) res.headers.containsKey('location'))
return false; return false;
else else
throw new AngelHttpException.notAuthenticated(); throw new AngelHttpException.notAuthenticated();

View file

@ -6,7 +6,7 @@ import 'options.dart';
AngelAuthCallback confirmPopupAuthentication({String eventName: 'token'}) { AngelAuthCallback confirmPopupAuthentication({String eventName: 'token'}) {
return (req, ResponseContext res, String jwt) async { return (req, ResponseContext res, String jwt) async {
res res
..contentType = ContentType.HTML ..contentType = new ContentType('text', 'html')
..write(''' ..write('''
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>

View file

@ -1,6 +1,5 @@
import 'dart:async'; import 'dart:async';
import 'package:dart2_constant/convert.dart'; import 'package:dart2_constant/convert.dart';
import 'dart:io';
import 'package:angel_framework/angel_framework.dart'; import 'package:angel_framework/angel_framework.dart';
import '../options.dart'; import '../options.dart';
import '../strategy.dart'; import '../strategy.dart';
@ -45,7 +44,7 @@ class LocalAuthStrategy extends AuthStrategy {
var verificationResult; var verificationResult;
if (allowBasic) { if (allowBasic) {
String authHeader = req.headers.value(HttpHeaders.AUTHORIZATION) ?? ""; String authHeader = req.headers.value('authorization') ?? "";
if (_rgxBasic.hasMatch(authHeader)) { if (_rgxBasic.hasMatch(authHeader)) {
String base64AuthString = _rgxBasic.firstMatch(authHeader).group(1); String base64AuthString = _rgxBasic.firstMatch(authHeader).group(1);
@ -82,14 +81,14 @@ class LocalAuthStrategy extends AuthStrategy {
if (verificationResult == false || verificationResult == null) { if (verificationResult == false || verificationResult == null) {
if (options.failureRedirect != null && if (options.failureRedirect != null &&
options.failureRedirect.isNotEmpty) { options.failureRedirect.isNotEmpty) {
res.redirect(options.failureRedirect, code: HttpStatus.UNAUTHORIZED); res.redirect(options.failureRedirect, code: 401);
return false; return false;
} }
if (forceBasic) { if (forceBasic) {
res res
..statusCode = 401 ..statusCode = 401
..headers[HttpHeaders.WWW_AUTHENTICATE] = 'Basic realm="$realm"' ..headers['www-authenticate'] = 'Basic realm="$realm"'
..end(); ..end();
} }

View file

@ -7,7 +7,8 @@ abstract class AuthStrategy {
String name; String name;
/// Authenticates or rejects an incoming user. /// 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. /// Determines whether a signed-in user can log out or not.
Future<bool> canLogout(RequestContext req, ResponseContext res); Future<bool> canLogout(RequestContext req, ResponseContext res);

View file

@ -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.1.1+6 version: 1.2.0
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
environment: environment:

View file

@ -7,7 +7,7 @@ import 'package:http/http.dart' as http;
import 'package:test/test.dart'; import 'package:test/test.dart';
final AngelAuth auth = new AngelAuth(); final AngelAuth auth = new AngelAuth();
var headers = <String, String>{HttpHeaders.ACCEPT: ContentType.JSON.mimeType}; var headers = <String, String>{'accept': 'application/json'};
AngelAuthOptions localOpts = new AngelAuthOptions( AngelAuthOptions localOpts = new AngelAuthOptions(
failureRedirect: '/failure', successRedirect: '/success'); failureRedirect: '/failure', successRedirect: '/success');
Map sampleUser = {'hello': 'world'}; Map sampleUser = {'hello': 'world'};
@ -46,8 +46,7 @@ main() async {
app.get('/success', "yep", middleware: ['auth']); app.get('/success', "yep", middleware: ['auth']);
app.get('/failure', "nope"); app.get('/failure', "nope");
HttpServer server = HttpServer server = await angelHttp.startServer('127.0.0.1', 0);
await angelHttp.startServer('127.0.0.1', 0);
url = "http://${server.address.host}:${server.port}"; url = "http://${server.address.host}:${server.port}";
basicAuthUrl = basicAuthUrl =
"http://username:password@${server.address.host}:${server.port}"; "http://username:password@${server.address.host}:${server.port}";
@ -71,25 +70,25 @@ main() async {
Map postData = {'username': 'username', 'password': 'password'}; Map postData = {'username': 'username', 'password': 'password'};
var response = await client.post("$url/login", var response = await client.post("$url/login",
body: json.encode(postData), body: json.encode(postData),
headers: {HttpHeaders.CONTENT_TYPE: ContentType.JSON.mimeType}); headers: {'content-type': 'application/json'});
expect(response.statusCode, equals(200)); expect(response.statusCode, equals(200));
expect(response.headers[HttpHeaders.LOCATION], equals('/success')); expect(response.headers['location'], equals('/success'));
}); });
test('failureRedirect', () async { test('failureRedirect', () async {
Map postData = {'username': 'password', 'password': 'username'}; Map postData = {'username': 'password', 'password': 'username'};
var response = await client.post("$url/login", var response = await client.post("$url/login",
body: json.encode(postData), body: json.encode(postData),
headers: {HttpHeaders.CONTENT_TYPE: ContentType.JSON.mimeType}); headers: {'content-type': 'application/json'});
print("Login response: ${response.body}"); print("Login response: ${response.body}");
expect(response.headers[HttpHeaders.LOCATION], equals('/failure')); expect(response.headers['location'], equals('/failure'));
expect(response.statusCode, equals(401)); expect(response.statusCode, equals(401));
}); });
test('allow basic', () async { test('allow basic', () async {
String authString = base64.encode("username:password".runes.toList()); String authString = base64.encode("username:password".runes.toList());
var response = await client.get("$url/hello", var response = await client
headers: {HttpHeaders.AUTHORIZATION: 'Basic $authString'}); .get("$url/hello", headers: {'authorization': 'Basic $authString'});
expect(response.body, equals('"Woo auth"')); expect(response.body, equals('"Woo auth"'));
}); });
@ -104,7 +103,6 @@ main() async {
.add(new LocalAuthStrategy(verifier, forceBasic: true, realm: 'test')); .add(new LocalAuthStrategy(verifier, forceBasic: true, realm: 'test'));
var response = await client.get("$url/hello", headers: headers); var response = await client.get("$url/hello", headers: headers);
print(response.headers); print(response.headers);
expect(response.headers[HttpHeaders.WWW_AUTHENTICATE], expect(response.headers['www-authenticate'], equals('Basic realm="test"'));
equals('Basic realm="test"'));
}); });
} }