Bump to 2.0.0-alpha
This commit is contained in:
parent
10dd869095
commit
a6b08ae7c4
8 changed files with 74 additions and 79 deletions
|
@ -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`.
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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}";
|
||||
|
|
Loading…
Reference in a new issue