Skip to content

Commit

Permalink
Merge pull request #731 from atsign-foundation/at_policy_1
Browse files Browse the repository at this point in the history
  • Loading branch information
gkc authored Dec 9, 2024
2 parents b65a3dc + b1e736e commit d214d0f
Show file tree
Hide file tree
Showing 23 changed files with 1,051 additions and 0 deletions.
1 change: 1 addition & 0 deletions .github/workflows/at_libraries.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ jobs:
- at_commons
- at_utils
- at_cli_commons
- at_policy
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2

Expand Down
7 changes: 7 additions & 0 deletions packages/at_policy/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# https://dart.dev/guides/libraries/private-files
# Created by `dart pub`
.dart_tool/

# Avoid committing pubspec.lock for library packages; see
# https://dart.dev/guides/libraries/private-files#pubspeclock.
pubspec.lock
3 changes: 3 additions & 0 deletions packages/at_policy/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
## 1.0.0

- Initial version.
29 changes: 29 additions & 0 deletions packages/at_policy/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
BSD 3-Clause License

Copyright (c) 2020, The @ Foundation
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.

2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.

3. Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 changes: 24 additions & 0 deletions packages/at_policy/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<a href="https://atsign.com#gh-light-mode-only"><img width=250px src="https://atsign.com/wp-content/uploads/2022/05/atsign-logo-horizontal-color2022.svg#gh-light-mode-only" alt="The Atsign Foundation"></a><a href="https://atsign.com#gh-dark-mode-only"><img width=250px src="https://atsign.com/wp-content/uploads/2023/08/atsign-logo-horizontal-reverse2022-Color.svg#gh-dark-mode-only" alt="The Atsign Foundation"></a>

[![pub package](https://img.shields.io/pub/v/at_policy)](https://pub.dev/packages/at_policy)
[![pub points](https://img.shields.io/pub/points/at_policy?logo=dart)](https://pub.dev/packages/at_onboarding_cli/score)
[![gitHub license](https://img.shields.io/badge/license-BSD3-blue.svg)](./LICENSE)

# at_policy

## Introduction
The at_policy library provides generic scaffolding for building policy
management services which policy enforcement endpoints communicate with via
atProtocol and therefore get all the benefits of using atProtocol - outbound
communication only, end-to-end encryption, using atSigns rather than IP
addresses

## Usage
See full worked examples in the [example](example/README.md) directory.

## Open source usage and contributions

This is freely licensed open source code, so feel free to use it as is, suggest
changes or enhancements or create your own version.
See [CONTRIBUTING.md](../../CONTRIBUTING.md) for detailed guidance on how to
set up tools, tests and make a pull request.
19 changes: 19 additions & 0 deletions packages/at_policy/analysis_options.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Defines a default set of lint rules enforced for
# projects at Google. For details and rationale,
# see https://pub.dev/packages/lints.
include: package:lints/recommended.yaml

# For lint rules and documentation, see http://dart-lang.github.io/linter/lints.
# Uncomment to specify additional rules.
linter:
rules:
annotate_overrides: true
prefer_final_fields: true
implicit_call_tearoffs: true
camel_case_types : true
unnecessary_string_interpolations : true
unnecessary_brace_in_string_interps: true
await_only_futures : true
unawaited_futures: true
depend_on_referenced_packages : false
avoid_function_literals_in_foreach_calls: true
3 changes: 3 additions & 0 deletions packages/at_policy/example/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# https://dart.dev/guides/libraries/private-files
# Created by `dart pub`
.dart_tool/
3 changes: 3 additions & 0 deletions packages/at_policy/example/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
## 1.0.0

- Initial version.
23 changes: 23 additions & 0 deletions packages/at_policy/example/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# at_policy examples

## Overview
- Imagine a client which is making a request to some service; it can make
three types of request
- `getPublicInfo`
- `getProtectedInfo`
- `getConfidentialInfo`
- The service needs to make a policy decision for each request - should it
respond with the info, or respond with a "not permitted" error? It
asks `policy` for information about how it should respond

## Programmes
- `client.dart`
- sends requests to `service`
- `service.dart`
- listens for requests from `client` and determines client intent
- sends message to `policy` requesting info about what policy decision it
should make regarding the client's intent
- `policy.dart`
- listens for requests from `service` with policy intents
- responds with the info that `service` requires in order to be able to
make a policy decision
19 changes: 19 additions & 0 deletions packages/at_policy/example/analysis_options.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Defines a default set of lint rules enforced for
# projects at Google. For details and rationale,
# see https://pub.dev/packages/lints.
include: package:lints/recommended.yaml

# For lint rules and documentation, see http://dart-lang.github.io/linter/lints.
# Uncomment to specify additional rules.
linter:
rules:
annotate_overrides: true
prefer_final_fields: true
implicit_call_tearoffs: true
camel_case_types : true
unnecessary_string_interpolations : true
unnecessary_brace_in_string_interps: true
await_only_futures : true
unawaited_futures: true
depend_on_referenced_packages : false
avoid_function_literals_in_foreach_calls: true
55 changes: 55 additions & 0 deletions packages/at_policy/example/bin/client.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import 'dart:async';
import 'dart:io';

import 'package:at_cli_commons/at_cli_commons.dart';
import 'package:at_client/at_client.dart';
import 'package:chalkdart/chalk.dart';
import 'common.dart';

void main(List<String> args) async {
try {
var argsParser = CLIBase.argsParser
..addOption('service-atsign',
mandatory: true,
help: "the atSign of the service this client is using");

var serviceAtsign = argsParser.parse(args)['service-atsign'];

var atClient = (await CLIBase.fromCommandLineArgs(args)).atClient;

var rpc = AtRpcClient(
atClient: atClient,
baseNameSpace: atClient.getPreferences()!.namespace!,
domainNameSpace: policyRequestNamespace,
serverAtsign: serviceAtsign);

stdout.writeln('Can make three types of request.');
for (final rt in RequestType.values) {
stdout.writeln(' ${rt.index + 1}. ${rt.name}');
}
stdout.writeln();
while (true) {
stdout.write(chalk.brightBlue('Enter request type number: '));
int reqType = int.parse(stdin.readLineSync()!.trim());
if (reqType < 1 || reqType > RequestType.values.length) {
stdout.writeln(chalk.red('Invalid request type'));
continue;
}

try {
var response = await rpc
.call({'reqType': RequestType.values[reqType - 1].name}).timeout(
Duration(seconds: 15));

stdout.writeln(chalk.green(response));
} on TimeoutException {
stderr.writeln(chalk.brightRed('timed out waiting for response'));
} catch (e) {
stderr.writeln(chalk.brightRed(e));
}
}
} catch (e) {
print(e);
print(CLIBase.argsParser.usage);
}
}
7 changes: 7 additions & 0 deletions packages/at_policy/example/bin/common.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
const String policyRequestNamespace = 'at_policy_example';

enum RequestType {
getPublicInfo,
getProtectedInfo,
getConfidentialInfo,
}
56 changes: 56 additions & 0 deletions packages/at_policy/example/bin/policy.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import 'dart:async';
import 'dart:io';

import 'package:at_cli_commons/at_cli_commons.dart';
import 'package:at_policy/at_policy.dart';
import 'package:chalkdart/chalk.dart';

void main(List<String> args) async {
try {
var atClient = (await CLIBase.fromCommandLineArgs(args)).atClient;

PolicyService ps = PolicyService(
baseNamespace: atClient.getPreferences()!.namespace!,
loggingAtsign: atClient.getCurrentAtSign()!,
allowList: {},
allowAll: true,
atClient: atClient,
handler: DemoPolicyRequestHandler(),
);

await ps.run();
} catch (e) {
print(e);
print(CLIBase.argsParser.usage);
}
}

class DemoPolicyRequestHandler implements PolicyRequestHandler {
@override
Future<PolicyResponse> getPolicyDetails(PolicyRequest req) async {
stdout.writeln(chalk.blue('Received request $req'));

stdout.write('(A)pprove or (D)eny? : ');
String decision = '';
while (decision.isEmpty) {
decision = stdin.readLineSync()!;
}
final bool approved = decision.toLowerCase().startsWith('a');

if (approved) {
List<PolicyDetail> details = [];
for (var i in req.intents) {
details.add(PolicyDetail(
intent: i.intent,
info: {'authorized': true},
));
}
return PolicyResponse(
message: 'manually approved',
policyDetails: details,
);
} else {
return PolicyResponse(message: 'nope', policyDetails: []);
}
}
}
97 changes: 97 additions & 0 deletions packages/at_policy/example/bin/service.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import 'dart:async';
import 'dart:io';

import 'package:at_cli_commons/at_cli_commons.dart';
import 'package:at_client/at_client.dart';
import 'package:at_policy/at_policy.dart';
import 'package:chalkdart/chalk.dart';
import 'common.dart';

void main(List<String> args) async {
try {
var argsParser = CLIBase.argsParser
..addOption('policy-atsign',
mandatory: true, help: "the atSign of the policy service");

var policyAtsign = argsParser.parse(args)['policy-atsign'];

var atClient = (await CLIBase.fromCommandLineArgs(args)).atClient;

var policyRpcClient = AtRpcClient(
atClient: atClient,
baseNameSpace: atClient.getPreferences()!.namespace!,
domainNameSpace: policyRequestNamespace,
serverAtsign: policyAtsign,
);

var thisRpcServer = AtRpc(
atClient: atClient,
baseNameSpace: atClient.getPreferences()!.namespace!,
domainNameSpace: policyRequestNamespace,
callbacks: DemoRpcServer(
myAtsign: atClient.getCurrentAtSign()!,
policyAtsign: policyAtsign,
policyRpcClient: policyRpcClient,
),
allowList: {},
allowAll: true,
);

thisRpcServer.start();
} catch (e) {
print(e);
print(CLIBase.argsParser.usage);
}
}

class DemoRpcServer implements AtRpcCallbacks {
String myAtsign;
String policyAtsign;
AtRpcClient policyRpcClient;

DemoRpcServer({
required this.myAtsign,
required this.policyAtsign,
required this.policyRpcClient,
});

@override
Future<AtRpcResp> handleRequest(AtRpcReq request, String fromAtSign) async {
stdout.writeln(chalk.blue('Received request ${request.toJson()}'));
RequestType rt;

try {
rt = RequestType.values.byName(request.payload['reqType']);
} catch (e) {
return AtRpcResp(
reqId: request.reqId,
respType: AtRpcRespType.error,
payload: {},
message: 'Invalid request ${request.payload}');
}

PolicyRequest polReq = PolicyRequest(
serviceAtsign: myAtsign,
serviceName: 'example_service_001',
serviceGroupName: 'example_service',
clientAtsign: fromAtSign,
intents: [PolicyIntent(intent: rt.name, params: {})]);

stderr.writeln('Sending policy check request : $polReq');
Map<String, dynamic> policyResponse =
await policyRpcClient.call(polReq.toJson());
stderr.writeln('Received policy info : $policyResponse');
return AtRpcResp(
reqId: request.reqId,
respType: AtRpcRespType.success,
payload: {'some': 'payload'},
message: 'Not yet implemented', // TODO
);
}

@override
Future<void> handleResponse(AtRpcResp response) async {
// Not expecting to receive responses
throw UnimplementedError();
}
}
18 changes: 18 additions & 0 deletions packages/at_policy/example/pubspec.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
name: at_policy_example
description: Simple at_policy usage examples
version: 1.0.0
publish_to: none

environment:
sdk: ^3.0.6

# Add regular dependencies here.
dependencies:
at_policy:
path: ..
at_cli_commons: ^1.2.1
at_client: ^3.3.0

dev_dependencies:
lints: ^3.0.0
test: ^1.24.9
5 changes: 5 additions & 0 deletions packages/at_policy/lib/at_policy.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
/// Policy management via atProtocol
library;

export 'src/policy/interfaces.dart';
export 'src/policy/models.dart';
Loading

0 comments on commit d214d0f

Please sign in to comment.