From 7978d8c78aa403cf1bc02d2146f418cb6966b37d Mon Sep 17 00:00:00 2001 From: Tobe O Date: Fri, 14 Dec 2018 02:40:37 -0500 Subject: [PATCH] get code tests --- lib/src/server.dart | 32 +++++++++- test/device_code_test.dart | 122 +++++++++++++++++++++++++++++++++++++ 2 files changed, 153 insertions(+), 1 deletion(-) create mode 100644 test/device_code_test.dart diff --git a/lib/src/server.dart b/lib/src/server.dart index ca28c3b5..dd5d7a8c 100644 --- a/lib/src/server.dart +++ b/lib/src/server.dart @@ -341,7 +341,9 @@ abstract class AuthorizationServer { var grantType = await _getParam(req, 'grant_type', state, body: true, throwIfEmpty: false); - if (grantType != 'authorization_code') { + if (grantType != 'authorization_code' && + grantType != 'urn:ietf:params:oauth:grant-type:device_code' && + grantType != null) { var match = _rgxBasic.firstMatch(req.headers.value('authorization') ?? ''); @@ -420,11 +422,39 @@ abstract class AuthorizationServer { response = await extensionGrants[grantType](req, res); } else if (grantType == null) { // This is a device code grant. + var clientId = await _getParam(req, 'client_id', state, body: true); + client = await findClient(clientId); + + if (client == null) { + throw new AuthorizationException( + new ErrorResponse( + ErrorResponse.unauthorizedClient, + 'Invalid "client_id" parameter.', + state, + ), + statusCode: 400, + ); + } + var scopes = await _getScopes(req, body: true); var deviceCodeResponse = await requestDeviceCode(client, scopes, req, res); return deviceCodeResponse.toJson(); } else if (grantType == 'urn:ietf:params:oauth:grant-type:device_code') { + var clientId = await _getParam(req, 'client_id', state, body: true); + client = await findClient(clientId); + + if (client == null) { + throw new AuthorizationException( + new ErrorResponse( + ErrorResponse.unauthorizedClient, + 'Invalid "client_id" parameter.', + state, + ), + statusCode: 400, + ); + } + var deviceCode = await _getParam(req, 'device_code', state, body: true); response = await exchangeDeviceCodeForToken( client, deviceCode, state, req, res); diff --git a/test/device_code_test.dart b/test/device_code_test.dart new file mode 100644 index 00000000..3bd08929 --- /dev/null +++ b/test/device_code_test.dart @@ -0,0 +1,122 @@ +import 'dart:async'; +import 'package:angel_framework/angel_framework.dart'; +import 'package:angel_test/angel_test.dart'; +import 'package:angel_oauth2/angel_oauth2.dart'; +import 'package:angel_validate/angel_validate.dart'; +import 'package:logging/logging.dart'; +import 'package:test/test.dart'; +import 'common.dart'; + +main() { + TestClient client; + + setUp(() async { + var app = new Angel(); + var oauth2 = new _AuthorizationServer(); + + app.group('/oauth2', (router) { + router + ..get('/authorize', oauth2.authorizationEndpoint) + ..post('/token', oauth2.tokenEndpoint); + }); + + app.logger = new Logger('angel_oauth2') + ..onRecord.listen((rec) { + print(rec); + if (rec.error != null) print(rec.error); + if (rec.stackTrace != null) print(rec.stackTrace); + }); + + app.errorHandler = (e, req, res) async { + res.json(e.toJson()); + }; + + client = await connectTo(app); + }); + + tearDown(() => client.close()); + + group('get initial code', () { + test('invalid client id', () async { + var response = await client.post('/oauth2/token', body: { + 'client_id': 'barr', + }); + print(response.body); + expect(response, hasStatus(400)); + }); + + test('valid client id, no scopes', () async { + var response = await client.post('/oauth2/token', body: { + 'client_id': 'foo', + }); + print(response.body); + expect( + response, + allOf( + hasStatus(200), + isJson({ + "device_code": "foo", + "user_code": "bar", + "verification_uri": "https://regiostech.com?scopes", + "expires_in": 3600 + }), + )); + }); + + test('valid client id, with scopes', () async { + var response = await client.post('/oauth2/token', body: { + 'client_id': 'foo', + 'scope': 'bar baz quux', + }); + print(response.body); + expect( + response, + allOf( + hasStatus(200), + isJson({ + "device_code": "foo", + "user_code": "bar", + "verification_uri": Uri.parse("https://regiostech.com").replace( + queryParameters: {'scopes': 'bar,baz,quux'}).toString(), + "expires_in": 3600 + }), + )); + }); + }); +} + +class _AuthorizationServer + extends AuthorizationServer { + @override + PseudoApplication findClient(String clientId) { + return clientId == pseudoApplication.id ? pseudoApplication : null; + } + + @override + Future verifyClient( + PseudoApplication client, String clientSecret) async { + return client.secret == clientSecret; + } + + @override + FutureOr requestDeviceCode(PseudoApplication client, + Iterable scopes, RequestContext req, ResponseContext res) { + return new DeviceCodeResponse( + 'foo', + 'bar', + Uri.parse('https://regiostech.com') + .replace(queryParameters: {'scopes': scopes.join(',')}), + 3600); + } + + @override + Future implicitGrant( + PseudoApplication client, + String redirectUri, + Iterable scopes, + String state, + RequestContext req, + ResponseContext res) async { + return new AuthorizationTokenResponse('foo'); + } +}