implicit
This commit is contained in:
parent
eb31a1a2c9
commit
2afe4deab0
7 changed files with 62 additions and 93 deletions
|
@ -1,3 +1,6 @@
|
||||||
|
# 2.3.0
|
||||||
|
* Remove `implicitGrant`, and inline it into `requestAuthorizationCode`.
|
||||||
|
|
||||||
# 2.2.0+1
|
# 2.2.0+1
|
||||||
* Parse+verify client for `authorization_code`.
|
* Parse+verify client for `authorization_code`.
|
||||||
|
|
||||||
|
|
|
@ -56,7 +56,8 @@ class _ExampleAuthorizationServer
|
||||||
Iterable<String> scopes,
|
Iterable<String> scopes,
|
||||||
String state,
|
String state,
|
||||||
RequestContext req,
|
RequestContext req,
|
||||||
ResponseContext res) {
|
ResponseContext res,
|
||||||
|
bool implicit) {
|
||||||
// TODO: In many cases, here you will render a view displaying to the user which scopes are being requested.
|
// TODO: In many cases, here you will render a view displaying to the user which scopes are being requested.
|
||||||
throw UnimplementedError();
|
throw UnimplementedError();
|
||||||
}
|
}
|
||||||
|
|
|
@ -89,34 +89,18 @@ abstract class AuthorizationServer<Client, User> {
|
||||||
/// Prompt the currently logged-in user to grant or deny access to the [client].
|
/// Prompt the currently logged-in user to grant or deny access to the [client].
|
||||||
///
|
///
|
||||||
/// In many applications, this will entail showing a dialog to the user in question.
|
/// In many applications, this will entail showing a dialog to the user in question.
|
||||||
FutureOr requestAuthorizationCode(
|
|
||||||
Client client,
|
|
||||||
String redirectUri,
|
|
||||||
Iterable<String> scopes,
|
|
||||||
String state,
|
|
||||||
RequestContext req,
|
|
||||||
ResponseContext res) {
|
|
||||||
throw AuthorizationException(
|
|
||||||
ErrorResponse(
|
|
||||||
ErrorResponse.unsupportedResponseType,
|
|
||||||
'Authorization code grants are not supported.',
|
|
||||||
state,
|
|
||||||
),
|
|
||||||
statusCode: 400,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Create an implicit authorization token.
|
|
||||||
///
|
///
|
||||||
/// Note that in cases where this is called, there is no guarantee
|
/// If [implicit] is `true`, then the client is requesting an *implicit grant*.
|
||||||
/// that the user agent has not been compromised.
|
/// Be aware of the security implications of this - do not handle them exactly
|
||||||
FutureOr<AuthorizationTokenResponse> implicitGrant(
|
/// the same.
|
||||||
|
FutureOr<void> requestAuthorizationCode(
|
||||||
Client client,
|
Client client,
|
||||||
String redirectUri,
|
String redirectUri,
|
||||||
Iterable<String> scopes,
|
Iterable<String> scopes,
|
||||||
String state,
|
String state,
|
||||||
RequestContext req,
|
RequestContext req,
|
||||||
ResponseContext res) {
|
ResponseContext res,
|
||||||
|
bool implicit) {
|
||||||
throw AuthorizationException(
|
throw AuthorizationException(
|
||||||
ErrorResponse(
|
ErrorResponse(
|
||||||
ErrorResponse.unsupportedResponseType,
|
ErrorResponse.unsupportedResponseType,
|
||||||
|
@ -227,9 +211,39 @@ abstract class AuthorizationServer<Client, User> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the [Uri] that a client can be redirected to in the case of an implicit grant.
|
||||||
|
Uri completeImplicitGrant(AuthorizationTokenResponse token, Uri redirectUri,
|
||||||
|
{String state}) {
|
||||||
|
var queryParameters = <String, String>{};
|
||||||
|
|
||||||
|
queryParameters.addAll({
|
||||||
|
'access_token': token.accessToken,
|
||||||
|
'token_type': 'bearer',
|
||||||
|
});
|
||||||
|
|
||||||
|
if (state != null) queryParameters['state'] = state;
|
||||||
|
|
||||||
|
if (token.expiresIn != null)
|
||||||
|
queryParameters['expires_in'] = token.expiresIn.toString();
|
||||||
|
|
||||||
|
if (token.scope != null) queryParameters['scope'] = token.scope.join(' ');
|
||||||
|
|
||||||
|
var fragment =
|
||||||
|
queryParameters.keys.fold<StringBuffer>(StringBuffer(), (buf, k) {
|
||||||
|
if (buf.isNotEmpty) buf.write('&');
|
||||||
|
return buf
|
||||||
|
..write(
|
||||||
|
'$k=' + Uri.encodeComponent(queryParameters[k]),
|
||||||
|
);
|
||||||
|
}).toString();
|
||||||
|
|
||||||
|
return redirectUri.replace(fragment: fragment);
|
||||||
|
}
|
||||||
|
|
||||||
/// A request handler that invokes the correct logic, depending on which type
|
/// A request handler that invokes the correct logic, depending on which type
|
||||||
/// of grant the client is requesting.
|
/// of grant the client is requesting.
|
||||||
Future authorizationEndpoint(RequestContext req, ResponseContext res) async {
|
Future<void> authorizationEndpoint(
|
||||||
|
RequestContext req, ResponseContext res) async {
|
||||||
String state = '';
|
String state = '';
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -241,7 +255,7 @@ abstract class AuthorizationServer<Client, User> {
|
||||||
return Pkce.fromJson(req.queryParameters, state: state);
|
return Pkce.fromJson(req.queryParameters, state: state);
|
||||||
});
|
});
|
||||||
|
|
||||||
if (responseType == 'code') {
|
if (responseType == 'code' || responseType == 'token') {
|
||||||
// Ensure client ID
|
// Ensure client ID
|
||||||
var clientId = await _getParam(req, 'client_id', state);
|
var clientId = await _getParam(req, 'client_id', state);
|
||||||
|
|
||||||
|
@ -262,68 +276,8 @@ abstract class AuthorizationServer<Client, User> {
|
||||||
// Grab scopes
|
// Grab scopes
|
||||||
var scopes = await _getScopes(req);
|
var scopes = await _getScopes(req);
|
||||||
|
|
||||||
return await requestAuthorizationCode(
|
return await requestAuthorizationCode(client, redirectUri, scopes,
|
||||||
client, redirectUri, scopes, state, req, res);
|
state, req, res, responseType == 'token');
|
||||||
}
|
|
||||||
|
|
||||||
if (responseType == 'token') {
|
|
||||||
var clientId = await _getParam(req, 'client_id', state);
|
|
||||||
var client = await findClient(clientId);
|
|
||||||
|
|
||||||
if (client == null) {
|
|
||||||
throw AuthorizationException(ErrorResponse(
|
|
||||||
ErrorResponse.unauthorizedClient,
|
|
||||||
'Unknown client "$clientId".',
|
|
||||||
state,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
var redirectUri = await _getParam(req, 'redirect_uri', state);
|
|
||||||
|
|
||||||
// Grab scopes
|
|
||||||
var scopes = await _getScopes(req);
|
|
||||||
var token =
|
|
||||||
await implicitGrant(client, redirectUri, scopes, state, req, res);
|
|
||||||
|
|
||||||
Uri target;
|
|
||||||
|
|
||||||
try {
|
|
||||||
target = Uri.parse(redirectUri);
|
|
||||||
var queryParameters = <String, String>{};
|
|
||||||
|
|
||||||
queryParameters.addAll({
|
|
||||||
'access_token': token.accessToken,
|
|
||||||
'token_type': 'bearer',
|
|
||||||
'state': state,
|
|
||||||
});
|
|
||||||
|
|
||||||
if (token.expiresIn != null)
|
|
||||||
queryParameters['expires_in'] = token.expiresIn.toString();
|
|
||||||
|
|
||||||
if (token.scope != null)
|
|
||||||
queryParameters['scope'] = token.scope.join(' ');
|
|
||||||
|
|
||||||
var fragment =
|
|
||||||
queryParameters.keys.fold<StringBuffer>(StringBuffer(), (buf, k) {
|
|
||||||
if (buf.isNotEmpty) buf.write('&');
|
|
||||||
return buf
|
|
||||||
..write(
|
|
||||||
'$k=' + Uri.encodeComponent(queryParameters[k]),
|
|
||||||
);
|
|
||||||
}).toString();
|
|
||||||
|
|
||||||
target = target.replace(fragment: fragment);
|
|
||||||
await res.redirect(target.toString());
|
|
||||||
return false;
|
|
||||||
} on FormatException {
|
|
||||||
throw AuthorizationException(
|
|
||||||
ErrorResponse(
|
|
||||||
ErrorResponse.invalidRequest,
|
|
||||||
'Invalid URI provided as "redirect_uri" parameter',
|
|
||||||
state,
|
|
||||||
),
|
|
||||||
statusCode: 400);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
throw AuthorizationException(
|
throw AuthorizationException(
|
||||||
|
|
|
@ -2,7 +2,7 @@ name: angel_oauth2
|
||||||
author: Tobe O <thosakwe@gmail.com>
|
author: Tobe O <thosakwe@gmail.com>
|
||||||
description: A class containing handlers that can be used within Angel to build a spec-compliant OAuth 2.0 server.
|
description: A class containing handlers that can be used within Angel to build a spec-compliant OAuth 2.0 server.
|
||||||
homepage: https://github.com/angel-dart/oauth2.git
|
homepage: https://github.com/angel-dart/oauth2.git
|
||||||
version: 2.2.0+1
|
version: 2.3.0
|
||||||
environment:
|
environment:
|
||||||
sdk: ">=2.0.0-dev <3.0.0"
|
sdk: ">=2.0.0-dev <3.0.0"
|
||||||
dependencies:
|
dependencies:
|
||||||
|
|
|
@ -139,7 +139,14 @@ class _Server extends AuthorizationServer<PseudoApplication, Map> {
|
||||||
Iterable<String> scopes,
|
Iterable<String> scopes,
|
||||||
String state,
|
String state,
|
||||||
RequestContext req,
|
RequestContext req,
|
||||||
ResponseContext res) async {
|
ResponseContext res,
|
||||||
|
bool implicit) async {
|
||||||
|
if (implicit) {
|
||||||
|
// Throw the default error on an implicit grant attempt.
|
||||||
|
return super.requestAuthorizationCode(
|
||||||
|
client, redirectUri, scopes, state, req, res, implicit);
|
||||||
|
}
|
||||||
|
|
||||||
if (state == 'hello')
|
if (state == 'hello')
|
||||||
return 'Hello ${pseudoApplication.id}:${pseudoApplication.secret}';
|
return 'Hello ${pseudoApplication.id}:${pseudoApplication.secret}';
|
||||||
|
|
||||||
|
|
|
@ -58,13 +58,16 @@ class _AuthorizationServer
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<AuthorizationTokenResponse> implicitGrant(
|
Future<void> requestAuthorizationCode(
|
||||||
PseudoApplication client,
|
PseudoApplication client,
|
||||||
String redirectUri,
|
String redirectUri,
|
||||||
Iterable<String> scopes,
|
Iterable<String> scopes,
|
||||||
String state,
|
String state,
|
||||||
RequestContext req,
|
RequestContext req,
|
||||||
ResponseContext res) async {
|
ResponseContext res,
|
||||||
return AuthorizationTokenResponse('foo');
|
bool implicit) async {
|
||||||
|
var tok = AuthorizationTokenResponse('foo');
|
||||||
|
var uri = completeImplicitGrant(tok, Uri.parse(redirectUri), state: state);
|
||||||
|
return res.redirect(uri);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -243,7 +243,8 @@ class _Server extends AuthorizationServer<PseudoApplication, Map> {
|
||||||
Iterable<String> scopes,
|
Iterable<String> scopes,
|
||||||
String state,
|
String state,
|
||||||
RequestContext req,
|
RequestContext req,
|
||||||
ResponseContext res) async {
|
ResponseContext res,
|
||||||
|
bool implicit) async {
|
||||||
req.container.make<Pkce>();
|
req.container.make<Pkce>();
|
||||||
return {'code': 'ok'};
|
return {'code': 'ok'};
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue