From 9a8f5d11114bbaa63de148d1e481aa8e8c2f7195 Mon Sep 17 00:00:00 2001 From: thosakwe Date: Mon, 23 Jan 2017 22:28:34 -0500 Subject: [PATCH] A LOT of work necessary... --- .DS_Store | Bin 0 -> 6148 bytes .gitignore | 1 + lib/.DS_Store | Bin 0 -> 6148 bytes lib/angel_auth_oauth2_server.dart | 0 lib/src.old/authorization_request.dart | 8 ++ lib/src.old/authorization_server.dart | 5 + lib/src.old/client.dart | 9 ++ lib/src.old/grant_type.dart | 16 ++++ lib/src.old/grants/authorization_code.dart | 13 +++ lib/src.old/resource_owner.dart | 6 ++ lib/src.old/resource_server.dart | 5 + lib/strategy.dart | 104 +++++++++++++++++++++ pubspec.yaml | 13 +++ 13 files changed, 180 insertions(+) create mode 100644 .DS_Store create mode 100644 lib/.DS_Store create mode 100644 lib/angel_auth_oauth2_server.dart create mode 100644 lib/src.old/authorization_request.dart create mode 100644 lib/src.old/authorization_server.dart create mode 100644 lib/src.old/client.dart create mode 100644 lib/src.old/grant_type.dart create mode 100644 lib/src.old/grants/authorization_code.dart create mode 100644 lib/src.old/resource_owner.dart create mode 100644 lib/src.old/resource_server.dart create mode 100644 lib/strategy.dart create mode 100644 pubspec.yaml diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..10f4d43063cf2afdea345ed0e8725c067b6d3ef7 GIT binary patch literal 6148 zcmeH~O=`nH427SXECStlndNM9fZkvT$q90S5(*^{5-7CmIeMRdHg&o#raXc4Mj8v- z-@;=7u>I%T3orrL&|R_fFf(Jm!W9>szfK>w>;3l5idTWBh?%i6VYXk}5)lvq5fA|p z5P<~|$Wt7f=LJ2J9z_I1U>OAb`_SmFy>z6;r-LCz0P33MFs@^kpf)d1d+A7Jg=RH9 zShZS=AzqJmYOCvd=}66XSPdUmcQ&75XqN4;#)M`)L_q{ZU`Ak-`Q+#Sk^bBKKWkAc z0wVCw2-x~?I_&vUb+$gdp4VTi>gz$L#^nq@egc^IQM{#xaliS3+Dk_&D>VHG1O^2W H_)`MkvH%f) literal 0 HcmV?d00001 diff --git a/.gitignore b/.gitignore index 7c280441..427e911b 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,7 @@ .packages .project .pub/ +.scripts-bin/ build/ **/packages/ diff --git a/lib/.DS_Store b/lib/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..89c0dbebb7f8a415a00c10c9e3246dbce154d313 GIT binary patch literal 6148 zcmeHKJxc>Y6r43F0yZfvx3xO-7aZa2#3op)Q9(h7^FDX? z25vt9q|Nwp1*`$A*n~;SjL1D3I`d><(ipqju^$e!E^+U%V+XB$fgT4ue-4xN_jskZ zM}q-->}WOEQX7?9tqxDr2m1HaMrv=k#sh0q`BnP{A9!bVGnwbkdGeW$oupV_Fc1s` z1Hr&aF~BohvN|`6J{SlFf`MNKv_E7vVe427>(;@pJ^_eJx~ovvTS7J2v2`qlj8Kx5 z60J1(6C+tU{n_(c$6{#ZNOfk8<1_y}UQ(T%{#?_MTEpmrfnZ?Dz{1S6&i@YFz^oyd;?KrCu{%! literal 0 HcmV?d00001 diff --git a/lib/angel_auth_oauth2_server.dart b/lib/angel_auth_oauth2_server.dart new file mode 100644 index 00000000..e69de29b diff --git a/lib/src.old/authorization_request.dart b/lib/src.old/authorization_request.dart new file mode 100644 index 00000000..7af02888 --- /dev/null +++ b/lib/src.old/authorization_request.dart @@ -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; +} \ No newline at end of file diff --git a/lib/src.old/authorization_server.dart b/lib/src.old/authorization_server.dart new file mode 100644 index 00000000..6abb9b9d --- /dev/null +++ b/lib/src.old/authorization_server.dart @@ -0,0 +1,5 @@ +/// The server issuing access tokens to the client after successfully +/// authenticating the resource owner and obtaining authorization. +abstract class AuthorizationServer { + +} \ No newline at end of file diff --git a/lib/src.old/client.dart b/lib/src.old/client.dart new file mode 100644 index 00000000..368d622e --- /dev/null +++ b/lib/src.old/client.dart @@ -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 {} diff --git a/lib/src.old/grant_type.dart b/lib/src.old/grant_type.dart new file mode 100644 index 00000000..2bed6195 --- /dev/null +++ b/lib/src.old/grant_type.dart @@ -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 GRANT_TYPES = const { + GrantType.AUTHORIZATION_CODE: 'authorization_code', + GrantType.IMPLICIT: 'implicit' + // TODO: RESOURCE_OWNER_PASSWORD_CREDENTIALS + // TODO: CLIENT_CREDENTIALS +}; diff --git a/lib/src.old/grants/authorization_code.dart b/lib/src.old/grants/authorization_code.dart new file mode 100644 index 00000000..843070cf --- /dev/null +++ b/lib/src.old/grants/authorization_code.dart @@ -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; +} diff --git a/lib/src.old/resource_owner.dart b/lib/src.old/resource_owner.dart new file mode 100644 index 00000000..af1b25bd --- /dev/null +++ b/lib/src.old/resource_owner.dart @@ -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 { + +} \ No newline at end of file diff --git a/lib/src.old/resource_server.dart b/lib/src.old/resource_server.dart new file mode 100644 index 00000000..c4c7cfee --- /dev/null +++ b/lib/src.old/resource_server.dart @@ -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 { + +} \ No newline at end of file diff --git a/lib/strategy.dart b/lib/strategy.dart new file mode 100644 index 00000000..f1eedeee --- /dev/null +++ b/lib/strategy.dart @@ -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 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 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 ensureAll(RequestContext req, Iterable required) { + if (required.any((str) => + !req.body.containsKey(str) || + (req.body[str] is! String && req.body[str].isEmpty))) + throw missingField(required); + + return required + .fold({}, (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 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 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 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 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']; + } +} diff --git a/pubspec.yaml b/pubspec.yaml new file mode 100644 index 00000000..f69e4adf --- /dev/null +++ b/pubspec.yaml @@ -0,0 +1,13 @@ +author: "Tobe O " +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"