A LOT of work necessary...
This commit is contained in:
parent
f8c59c98dc
commit
9a8f5d1111
13 changed files with 180 additions and 0 deletions
BIN
.DS_Store
vendored
Normal file
BIN
.DS_Store
vendored
Normal file
Binary file not shown.
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -5,6 +5,7 @@
|
|||
.packages
|
||||
.project
|
||||
.pub/
|
||||
.scripts-bin/
|
||||
build/
|
||||
**/packages/
|
||||
|
||||
|
|
BIN
lib/.DS_Store
vendored
Normal file
BIN
lib/.DS_Store
vendored
Normal file
Binary file not shown.
0
lib/angel_auth_oauth2_server.dart
Normal file
0
lib/angel_auth_oauth2_server.dart
Normal file
8
lib/src.old/authorization_request.dart
Normal file
8
lib/src.old/authorization_request.dart
Normal 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;
|
||||
}
|
5
lib/src.old/authorization_server.dart
Normal file
5
lib/src.old/authorization_server.dart
Normal 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
9
lib/src.old/client.dart
Normal 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> {}
|
16
lib/src.old/grant_type.dart
Normal file
16
lib/src.old/grant_type.dart
Normal 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
|
||||
};
|
13
lib/src.old/grants/authorization_code.dart
Normal file
13
lib/src.old/grants/authorization_code.dart
Normal 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;
|
||||
}
|
6
lib/src.old/resource_owner.dart
Normal file
6
lib/src.old/resource_owner.dart
Normal 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 {
|
||||
|
||||
}
|
5
lib/src.old/resource_server.dart
Normal file
5
lib/src.old/resource_server.dart
Normal 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
104
lib/strategy.dart
Normal 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
13
pubspec.yaml
Normal 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"
|
Loading…
Reference in a new issue