// Copyright (C) 2022 WYATT GROUP // Please see the AUTHORS file for details. // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see . import 'dart:async'; import 'dart:io'; import 'package:wyatt_http_client/wyatt_http_client.dart'; String lastToken = ''; int token = 0; void printAuth(HttpRequest req) { print( 'Authorization => ' "${req.headers.value('Authorization') ?? 'no authorization header'}", ); } Future handleBasic(HttpRequest req) async { printAuth(req); } Future handleBasicNegotiate(HttpRequest req) async { if (req.headers.value('Authorization') == null) { req.response.statusCode = HttpStatus.unauthorized.statusCode; req.response.headers.set(HeaderKeys.wwwAuthenticate, 'Basic realm="Wyatt"'); print(req.response.headers.value('WWW-Authenticate')); return req.response.close(); } printAuth(req); } Future handleBearer(HttpRequest req) async { printAuth(req); } Future handleDigest(HttpRequest req) async { if (req.headers.value('Authorization') == null) { req.response.statusCode = HttpStatus.unauthorized.statusCode; req.response.headers.set( 'WWW-Authenticate', 'Digest realm="Wyatt", ' 'qop="auth,auth-int", ' 'nonce="dcd98b7102dd2f0e8b11d0f600bfb0c093", ' 'opaque="5ccc069c403ebaf9f0171e9517f40e41"', ); print(req.response.headers.value('WWW-Authenticate')); return req.response.close(); } printAuth(req); } Future handleUnsafe(HttpRequest req) async { print( 'Query parameters => ' '${req.uri.queryParameters.toString()}', ); } Future handleOauth2RefreshToken(HttpRequest req) async { final action = req.uri.queryParameters['action']; if (action == null) { printAuth(req); } switch (action) { case 'login': if (req.method == 'POST') { token++; req.response.write( '{"accessToken": "access-token-awesome$token", ' '"refreshToken": "refresh-token-awesome$token"}', ); } break; case 'refresh': printAuth(req); if (req.method == 'GET') { token++; req.response.write('{"accessToken": "access-token-refreshed$token"}'); } break; case 'access-denied': final String receivedToken = req.headers.value('Authorization') ?? ''; if (receivedToken != '' && lastToken != '' && receivedToken != lastToken) { lastToken = receivedToken; printAuth(req); return req.response.close(); } else { lastToken = receivedToken; req.response.statusCode = HttpStatus.unauthorized.statusCode; return req.response.close(); } default: break; } } Future server() async { final server = await HttpServer.bind(InternetAddress.anyIPv6, 8080); var error = 0; var token = 0; await server.forEach((HttpRequest request) { print('[${request.method}] ${request.uri}'); switch (request.uri.path) { case '/test/basic-test': handleBasic(request); break; case '/test/basic-test-with-negotiate': handleBasicNegotiate(request); break; case '/test/digest-test': handleDigest(request); break; case '/test/apikey-test': handleBearer(request); break; case '/test/bearer-test': handleBearer(request); break; case '/test/unsafe-test': handleUnsafe(request); break; case '/test/oauth2-test': handleOauth2RefreshToken(request); break; case '/test/bearer-login': if (request.method == 'POST') { request.response.write('{"token": "access-token-test"}'); } break; case '/test/oauth2-test-error': error++; print('Error $error'); if (error >= 3) { print('Authorized'); error = 0; } else { request.response.statusCode = HttpStatus.unauthorized.statusCode; } break; case '/test/oauth2-test-timeout': error++; print('Error $error'); request.response.statusCode = HttpStatus.unauthorized.statusCode; break; case '/test/oauth2-login': if (request.method == 'POST') { token++; request.response.write( '{"accessToken": "access-token-awesome$token", ' '"refreshToken": "refresh-token-awesome$token"}', ); } break; case '/test/oauth2-refresh': print( 'Authorization => ' "${request.headers.value('Authorization') ?? 'no refresh token'}", ); if (request.method == 'GET') { token++; request.response .write('{"accessToken": "access-token-refreshed$token"}'); } break; case '/test/oauth2-refresh-error': request.response.statusCode = HttpStatus.unauthorized.statusCode; break; default: print(' => Unknown path or method'); request.response.statusCode = HttpStatus.notFound.statusCode; } request.response.close(); print('===================='); }); } Future main() async { unawaited(server()); final base = 'localhost:8080'; final uriPrefix = UriPrefixMiddleware( protocol: Protocols.http, authority: base, ); final jsonEncoder = BodyToJsonMiddleware(); final logger = SimpleLoggerMiddleware(); // Basic final basicAuth = BasicAuthMiddleware( username: 'username', password: 'password', ); final basic = MiddlewareClient( pipeline: Pipeline.fromIterable([ uriPrefix, basicAuth, logger, ]), ); await basic.get(Uri.parse('/test/basic-test')); // Digest final digestAuth = DigestAuthMiddleware( username: 'Mufasa', password: 'Circle Of Life', ); final digest = MiddlewareClient( pipeline: Pipeline.fromIterable([ uriPrefix, digestAuth, logger, ]), ); await digest.get(Uri.parse('/test/digest-test')); // // Bearer // final bearer = BearerAuthenticationClient( // token: 'access-token-test', // inner: restClient, // ); // await bearer.get(Uri.parse('/test/bearer-test')); // // API Key // final apiKey = BearerAuthenticationClient( // token: 'awesome-api-key', // authenticationMethod: 'ApiKey', // inner: restClient, // ); // await apiKey.get(Uri.parse('/test/apikey-test')); // Unsafe URL final unsafeAuth = UnsafeAuthMiddleware( username: 'Mufasa', password: 'Circle Of Life', ); final unsafe = MiddlewareClient( pipeline: Pipeline.fromIterable([ uriPrefix, unsafeAuth, logger, ]), ); await unsafe.get(Uri.parse('/test/unsafe-test')); // OAuth2 final refreshTokenAuth = RefreshTokenAuthMiddleware( authorizationEndpoint: '/test/oauth2-test?action=login', tokenEndpoint: '/test/oauth2-test?action=refresh', accessTokenParser: (body) => body['accessToken']! as String, refreshTokenParser: (body) => body['refreshToken']! as String, ); final refreshToken = MiddlewareClient( pipeline: Pipeline.fromIterable([ uriPrefix, jsonEncoder, refreshTokenAuth, logger, ]), ); await refreshToken.get(Uri.parse('/test/oauth2-test')); // Login await refreshToken.post( Uri.parse('/test/oauth2-test'), body: { 'username': 'username', 'password': 'password', }, ); await refreshToken.get(Uri.parse('/test/oauth2-test')); // await refreshToken.refresh(); // await refreshToken.get(Uri.parse('/test/oauth2-test')); // await refreshToken.get(Uri.parse('/test/oauth2-test?action=access-denied')); exit(0); }