A LOT of work necessary...

This commit is contained in:
thosakwe 2017-01-23 22:28:34 -05:00
parent f8c59c98dc
commit 9a8f5d1111
13 changed files with 180 additions and 0 deletions

BIN
.DS_Store vendored Normal file

Binary file not shown.

1
.gitignore vendored
View file

@ -5,6 +5,7 @@
.packages
.project
.pub/
.scripts-bin/
build/
**/packages/

BIN
lib/.DS_Store vendored Normal file

Binary file not shown.

View file

View file

@ -0,0 +1,8 @@
import 'grant_type.dart';
/// An authorization grant is a credential representing the resource
/// owner's authorization (to access its protected resources) used by the
/// client to obtain an access token.
abstract class AuthorizationRequest {
GrantType get type;
}

View file

@ -0,0 +1,5 @@
/// The server issuing access tokens to the client after successfully
/// authenticating the resource owner and obtaining authorization.
abstract class AuthorizationServer {
}

9
lib/src.old/client.dart Normal file
View file

@ -0,0 +1,9 @@
import 'dart:async';
import 'authorization_request.dart';
/// An application making protected resource requests on behalf of the
/// resource owner and with its authorization. The term "client" does
/// not imply any particular implementation characteristics (e.g.,
/// whether the application executes on a server, a desktop, or other
/// devices).
abstract class Client extends Stream<AuthorizationRequest> {}

View file

@ -0,0 +1,16 @@
/// The four grant types defined in the OAuth2 specification.
enum GrantType {
AUTHORIZATION_CODE,
IMPLICIT,
RESOURCE_OWNER_PASSWORD_CREDENTIALS,
CLIENT_CREDENTIALS,
// TODO: OTHER
}
/// `String` representations of the four main grant types.
const Map<GrantType, String> GRANT_TYPES = const {
GrantType.AUTHORIZATION_CODE: 'authorization_code',
GrantType.IMPLICIT: 'implicit'
// TODO: RESOURCE_OWNER_PASSWORD_CREDENTIALS
// TODO: CLIENT_CREDENTIALS
};

View file

@ -0,0 +1,13 @@
import '../authorization_request.dart';
import '../grant_type.dart';
/// The authorization code is obtained by using an authorization server
/// as an intermediary between the client and resource owner. Instead of
/// requesting authorization directly from the resource owner, the client
/// directs the resource owner to an authorization server (via its
/// user-agent as defined in [RFC2616]), which in turn directs the
/// resource owner back to the client with the authorization code.
class AuthorizationCodeGrantRequest implements AuthorizationRequest {
@override
GrantType get type => GrantType.AUTHORIZATION_CODE;
}

View file

@ -0,0 +1,6 @@
/// An entity capable of granting access to a protected resource.
/// When the resource owner is a person, it is referred to as an
/// end-user.
class ResourceOwner {
}

View file

@ -0,0 +1,5 @@
/// The server hosting the protected resources, capable of accepting
/// and responding to protected resource requests using access tokens.
abstract class ResourceServer {
}

104
lib/strategy.dart Normal file
View file

@ -0,0 +1,104 @@
import 'dart:async';
import 'package:angel_auth/angel_auth.dart';
import 'package:angel_framework/angel_framework.dart';
abstract class Oauth2ServerStrategy extends AuthStrategy {
@override
final String name = 'oauth2-server';
@override
Future<bool> canLogout(RequestContext req, ResponseContext res) async => true;
/// Convey to the user that one or more fields are missing.
///
/// [field] can be a single value, or an `Iterable`.
AngelHttpException missingField(field) {
Iterable<String> fields =
field is Iterable ? field.map((x) => x.toString()) : [field.toString()];
if (field == null)
throw new ArgumentError.notNull('field');
else if (fields.isEmpty)
throw new ArgumentError(
'Cannot provide an empty list of missing fields.');
return new AngelHttpException.badRequest(
message:
"Missing one or more of the following fields: " + fields.join(','));
}
/// Returns a map containing the given values of all [required] keys,
/// or throws a [missingField] error if any are missing.
Map<String, String> ensureAll(RequestContext req, Iterable<String> required) {
if (required.any((str) =>
!req.body.containsKey(str) ||
(req.body[str] is! String && req.body[str].isEmpty)))
throw missingField(required);
return required
.fold(<String, String>{}, (map, key) => map..[key] = req.query[key]);
}
@override
Future authenticate(RequestContext req, ResponseContext res,
[AngelAuthOptions options]) {
if (req.body['response_type'] is! String) {
return new Future.error(missingField('response_type'));
} else {
String responseType = req.body['response_type'];
switch (responseType) {
case 'code':
return authorizationCodeGrant(req, res);
case 'authorization_code':
return accessTokenRequest(req, res);
default:
throw new AngelHttpException.badRequest(
message: "Unsupported grant type '$responseType'.");
}
}
}
/// Generates an authorization code for a client who is requesting access.
Future<String> createAuthorizationCode(
String clientId, String redirectUri, String scope, String state);
/// Generates a redirect URL for a client who is requesting access via
/// an authorization code grant request.
///
/// Do not include a query component, or trailing slashes.
Future<String> createRedirectUrl(
String clientId, String redirectUri, String scope, String state);
/// Performs an authorization code grant.
Future authorizationCodeGrant(RequestContext req, ResponseContext res) async {
var data = ensureAll(req, ['client_id']);
String clientId = data['client_id'];
String redirectUri = req.body['redirect_uri'],
scope = req.body['scope'],
state = req.body['state'];
var redirect = await createRedirectUrl(clientId, redirectUri?.toString(),
scope?.toString(), state?.toString());
var code = await createAuthorizationCode(clientId, redirectUri?.toString(),
scope?.toString(), state?.toString());
List<String> query = ['code=' + Uri.encodeQueryComponent(code)];
if (state?.isNotEmpty == true)
query.add('state=' + Uri.encodeQueryComponent(state));
res.redirect(redirect + '?' + query.join('&'));
// TODO: Support error responses: https://tools.ietf.org/html/rfc6749#section-4
}
/// Awards an access token to a successfully authenticated user.
Future<AccessTokenInfo> accessTokenRequest(
RequestContext req, ResponseContext res) async {
var data = ensureAll(req, ['code', 'redirect_uri', 'client_id']);
String code = data['code'],
redirectUri = data['redirect_uri'],
clientId = data['client_id'];
}
}

13
pubspec.yaml Normal file
View file

@ -0,0 +1,13 @@
author: "Tobe O <thosakwe@gmail.com>"
description: "angel_auth strategy for in-house OAuth2 login."
homepage: "https://github.com/thosakwe/oauth2_server.git"
name: "angel_auth_oauth2_server"
version: "0.0.0"
dependencies:
angel_auth: "^1.0.0-dev"
angel_framework: "^1.0.0-dev"
dev_dependencies:
angel_test: "^1.0.0-dev"
http: "^0.11.3+9"
oauth2: "^1.0.2"
test: "^0.12.18+1"