Bump to 2.0.0-alpha

This commit is contained in:
Tobe O 2018-08-26 19:11:37 -04:00
parent 10dd869095
commit a6b08ae7c4
8 changed files with 74 additions and 79 deletions

View file

@ -1,3 +1,9 @@
# 2.0.0-alpha
* Depend on Dart 2 and Angel 2.
* Remove `dart2_constant`.
* Remove `requireAuth`.
* Remove `userKey`, instead favoring generic parameters.
# 1.2.0
* Deprecate `requireAuth`, in favor of `requireAuthentication`.
* Allow configuring of the `userKey`.

View file

@ -3,24 +3,19 @@ import 'package:angel_framework/angel_framework.dart';
/// Forces Basic authentication over the requested resource, with the given [realm] name, if no JWT is present.
///
/// [realm] defaults to `'angel_auth'`.
RequestHandler forceBasicAuth({String realm, String userKey: 'user'}) {
RequestHandler forceBasicAuth<User>({String realm}) {
return (RequestContext req, ResponseContext res) async {
if (req.properties.containsKey(userKey)) return true;
if (req.container.has<User>()) return true;
res
..statusCode = 401
..headers['www-authenticate'] = 'Basic realm="${realm ?? 'angel_auth'}"'
..end();
return false;
..close();
};
}
/// Use [requireAuthentication] instead.
@deprecated
final RequestMiddleware requireAuth = requireAuthentication(userKey: 'user');
/// Restricts access to a resource via authentication.
RequestMiddleware requireAuthentication({String userKey: 'user'}) {
RequestHandler requireAuthentication<User>() {
return (RequestContext req, ResponseContext res,
{bool throwError: true}) async {
bool _reject(ResponseContext res) {
@ -31,7 +26,7 @@ RequestMiddleware requireAuthentication({String userKey: 'user'}) {
return false;
}
if (req.properties.containsKey(userKey) || req.method == 'OPTIONS')
if (req.container.has<User>() || req.method == 'OPTIONS')
return true;
else
return _reject(res);

View file

@ -3,7 +3,6 @@ import 'dart:io';
import 'dart:math' as Math;
import 'package:angel_framework/angel_framework.dart';
import 'package:crypto/crypto.dart';
import 'middleware/require_auth.dart';
import 'auth_token.dart';
import 'defs.dart';
import 'options.dart';
@ -38,15 +37,6 @@ class AngelAuth<T> {
/// Only applies if [allowCookie] is `true`.
final String cookiePath;
/// The name to register [requireAuthentication] as. Default: `auth`.
@deprecated
String middlewareName;
/// The name to inject authenticated users as.
///
/// Defaults to `'user'`.
final String userKey;
/// 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.
///
/// This is a security provision. Even if a user's JWT is stolen, a remote attacker will not be able to impersonate anyone.
@ -90,10 +80,8 @@ class AngelAuth<T> {
this.allowTokenInQuery: true,
this.enforceIp: true,
this.cookieDomain,
this.userKey: 'user',
this.cookiePath: '/',
this.secureCookies: true,
this.middlewareName: 'auth',
this.reviveTokenEndpoint: "/auth/token"})
: super() {
_hs256 = new Hmac(sha256, (jwtKey ?? _randomString()).codeUnits);
@ -108,11 +96,9 @@ class AngelAuth<T> {
throw new StateError(
'An `AngelAuth` plug-in was called without its `deserializer` being set. All authentication will fail.');
app.container.singleton(this);
if (runtimeType != AngelAuth) app.container.singleton(this, as: AngelAuth);
// ignore: deprecated_member_use
app.registerMiddleware(middlewareName, requireAuthentication());
app.container.registerSingleton(this);
if (runtimeType != AngelAuth)
app.container.registerSingleton(this, as: AngelAuth);
if (reviveTokenEndpoint != null) {
app.post(reviveTokenEndpoint, reviveJwt);
@ -123,10 +109,11 @@ class AngelAuth<T> {
});
}
void _apply(RequestContext req, ResponseContext res, AuthToken token, user) {
req
..inject(AuthToken, req.properties['token'] = token)
..inject(user.runtimeType, req.properties[userKey] = user);
void _apply(
RequestContext req, ResponseContext res, AuthToken token, T user) {
req.container
..registerSingleton<AuthToken>(token)
..registerSingleton<T>(user);
if (allowCookie == true) {
_addProtectedCookie(res, 'token', token.serialize(_hs256));
@ -176,8 +163,9 @@ class AngelAuth<T> {
} else if (allowCookie &&
req.cookies.any((cookie) => cookie.name == "token")) {
return req.cookies.firstWhere((cookie) => cookie.name == "token").value;
} else if (allowTokenInQuery && req.query['token'] is String) {
return req.query['token']?.toString();
} else if (allowTokenInQuery &&
req.uri.queryParameters['token'] is String) {
return req.uri.queryParameters['token']?.toString();
}
return null;
@ -214,7 +202,7 @@ class AngelAuth<T> {
var jwt = getJwt(req);
if (jwt == null) {
var body = await req.lazyBody();
var body = await req.parseBody();
jwt = body['token']?.toString();
}
if (jwt == null) {
@ -282,14 +270,14 @@ class AngelAuth<T> {
orElse: () =>
throw new ArgumentError('No strategy "$name" found.'));
var hasExisting = req.properties.containsKey(userKey);
var hasExisting = req.container.has<T>();
var result = hasExisting
? req.properties[userKey]
: await strategy.authenticate(req, res, options);
? req.container.make<T>()
: await strategy.authenticate(req, res, options) as T;
if (result == true)
return result;
else if (result != false) {
var userId = await serializer(result as T);
var userId = await serializer(result);
// Create JWT
var token = new AuthToken(
@ -297,8 +285,8 @@ class AngelAuth<T> {
var jwt = token.serialize(_hs256);
if (options?.tokenCallback != null) {
var r = await options.tokenCallback(
req, res, token, req.properties[userKey] = result);
req.container.registerSingleton<T>(result);
var r = await options.tokenCallback(req, res, token, result);
if (r != null) return r;
jwt = token.serialize(_hs256);
}
@ -319,8 +307,8 @@ class AngelAuth<T> {
} else if (options?.canRespondWithJson != false &&
req.accepts('application/json')) {
var user = hasExisting
? result as T
: await deserializer(await serializer(result as T));
? result
: await deserializer(await serializer(result));
_onLogin.add(user);
return {"data": user, "token": jwt};
}
@ -365,7 +353,7 @@ class AngelAuth<T> {
}
/// Log an authenticated user out.
RequestMiddleware logout([AngelAuthOptions options]) {
RequestHandler logout([AngelAuthOptions options]) {
return (RequestContext req, ResponseContext res) async {
for (AuthStrategy strategy in strategies) {
if (!(await strategy.canLogout(req, res))) {
@ -379,11 +367,10 @@ class AngelAuth<T> {
}
}
var user = req.grab(userKey);
if (user != null) _onLogout.add(user as T);
req.injections..remove(AuthToken)..remove(userKey);
req.properties.remove(userKey);
if (req.container.has<T>()) {
var user = req.container.make<T>();
_onLogout.add(user);
}
if (allowCookie == true) {
res.cookies.removeWhere((cookie) => cookie.name == "token");

View file

@ -1,12 +1,12 @@
import 'dart:io';
import 'package:angel_framework/angel_framework.dart';
import 'package:http_parser/http_parser.dart';
import 'options.dart';
/// Displays a default callback page to confirm authentication via popups.
AngelAuthCallback confirmPopupAuthentication({String eventName: 'token'}) {
return (req, ResponseContext res, String jwt) async {
res
..contentType = new ContentType('text', 'html')
..contentType = new MediaType('text', 'html')
..write('''
<!DOCTYPE html>
<html>

View file

@ -61,7 +61,7 @@ class LocalAuthStrategy extends AuthStrategy {
res
..statusCode = 401
..headers['www-authenticate'] = 'Basic realm="$realm"'
..end();
..close();
return false;
}
@ -70,11 +70,11 @@ class LocalAuthStrategy extends AuthStrategy {
}
if (verificationResult == null) {
await req.parse();
if (_validateString(req.body[usernameField]?.toString()) &&
_validateString(req.body[passwordField]?.toString())) {
verificationResult = await verifier(req.body[usernameField]?.toString(),
req.body[passwordField]?.toString());
var body = await req.parseBody();
if (_validateString(body[usernameField]?.toString()) &&
_validateString(body[passwordField]?.toString())) {
verificationResult = await verifier(
body[usernameField]?.toString(), body[passwordField]?.toString());
}
}
@ -89,7 +89,7 @@ class LocalAuthStrategy extends AuthStrategy {
res
..statusCode = 401
..headers['www-authenticate'] = 'Basic realm="$realm"'
..end();
..close();
}
return false;

View file

@ -1,16 +1,15 @@
name: angel_auth
description: A complete authentication plugin for Angel.
version: 1.2.0
version: 2.0.0-alpha
author: Tobe O <thosakwe@gmail.com>
homepage: https://github.com/angel-dart/angel_auth
environment:
sdk: ">=1.8.0 <3.0.0"
sdk: ">=2.0.0-dev <3.0.0"
dependencies:
angel_framework: ^1.1.0-alpha
angel_framework: ^2.0.0-alpha
crypto: ^2.0.0
dart2_constant: ^1.0.0
dev_dependencies:
http: ^0.11.0
io: ^0.3.2
logging: ^0.11.0
test: ^0.12.0
test: ^1.0.0

View file

@ -1,7 +1,6 @@
import 'dart:io';
import 'package:angel_auth/angel_auth.dart';
import 'package:angel_framework/angel_framework.dart';
import 'package:angel_framework/common.dart';
import 'package:dart2_constant/convert.dart';
import 'package:http/http.dart' as http;
import 'package:io/ansi.dart';
@ -17,7 +16,7 @@ class User extends Model {
main() {
Angel app;
AngelHttp angelHttp;
AngelAuth auth;
AngelAuth<User> auth;
http.Client client;
HttpServer server;
String url;
@ -26,7 +25,7 @@ main() {
hierarchicalLoggingEnabled = true;
app = new Angel();
angelHttp = new AngelHttp(app);
app.use('/users', new TypedService<User>(new MapService()));
app.use('/users', new MapService());
var oldErrorHandler = app.errorHandler;
app.errorHandler = (e, req, res) {
@ -58,7 +57,7 @@ main() {
(id) async => await app.service('users').read(id) as User;
await app.configure(auth.configureServer);
app.use(auth.decodeJwt);
app.fallback(auth.decodeJwt);
auth.strategies.add(new LocalAuthStrategy((username, password) async {
final List<User> users = await app.service('users').index();
@ -75,14 +74,19 @@ main() {
new AngelAuthOptions(callback: (req, res, token) {
res
..write('Hello!')
..end();
..close();
})));
app.chain((RequestContext req) {
req.properties['user'] =
new User(username: req.params['name']?.toString());
return true;
}).post('/existing/:name', auth.authenticate('local'));
app.chain([
(req, res) {
req.container.registerSingleton<User>(
new User(username: req.params['name']?.toString()));
return true;
}
]).post(
'/existing/:name',
auth.authenticate('local'),
);
client = new http.Client();
server = await angelHttp.startServer();

View file

@ -6,11 +6,12 @@ import 'package:dart2_constant/convert.dart';
import 'package:http/http.dart' as http;
import 'package:test/test.dart';
final AngelAuth auth = new AngelAuth();
final AngelAuth<Map<String, String>> auth =
new AngelAuth<Map<String, String>>();
var headers = <String, String>{'accept': 'application/json'};
AngelAuthOptions localOpts = new AngelAuthOptions(
failureRedirect: '/failure', successRedirect: '/success');
Map sampleUser = {'hello': 'world'};
Map<String, String> sampleUser = {'hello': 'world'};
Future verifier(String username, String password) async {
if (username == 'username' && password == 'password') {
@ -25,7 +26,7 @@ Future wireAuth(Angel app) async {
auth.strategies.add(new LocalAuthStrategy(verifier));
await app.configure(auth.configureServer);
app.use(auth.decodeJwt);
app.fallback(auth.decodeJwt);
}
main() async {
@ -40,11 +41,14 @@ main() async {
app = new Angel();
angelHttp = new AngelHttp(app, useZone: false);
await app.configure(wireAuth);
app.get('/hello', 'Woo auth', middleware: [auth.authenticate('local')]);
app.post('/login', 'This should not be shown',
app.get('/hello', (req, res) => 'Woo auth',
middleware: [auth.authenticate('local')]);
app.post('/login', (req, res) => 'This should not be shown',
middleware: [auth.authenticate('local', localOpts)]);
app.get('/success', "yep", middleware: ['auth']);
app.get('/failure', "nope");
app.get('/success', (req, res) => "yep", middleware: [
requireAuthentication<Map<String, String>>(),
]);
app.get('/failure', (req, res) => "nope");
HttpServer server = await angelHttp.startServer('127.0.0.1', 0);
url = "http://${server.address.host}:${server.port}";