cedar_policy_cli/command/
authorize.rs1use std::{path::Path, time::Instant};
18
19use cedar_policy::{Authorizer, Decision, Entities, PolicySet, Response};
20use clap::Args;
21use miette::Report;
22
23use crate::{load_entities, CedarExitCode, OptionalSchemaArgs, PoliciesArgs, RequestArgs};
24
25#[derive(Args, Debug)]
26pub struct AuthorizeArgs {
27 #[command(flatten)]
29 pub request: RequestArgs,
30 #[command(flatten)]
32 pub policies: PoliciesArgs,
33 #[command(flatten)]
38 pub schema: OptionalSchemaArgs,
39 #[arg(long = "entities", value_name = "FILE")]
41 pub entities_file: String,
42 #[arg(short, long)]
44 pub verbose: bool,
45 #[arg(short, long)]
47 pub timing: bool,
48}
49
50pub fn authorize(args: &AuthorizeArgs) -> CedarExitCode {
51 println!();
52 let ans = execute_request(
53 &args.request,
54 &args.policies,
55 &args.entities_file,
56 &args.schema,
57 args.timing,
58 );
59 match ans {
60 Ok(ans) => {
61 let status = match ans.decision() {
62 Decision::Allow => {
63 println!("ALLOW");
64 CedarExitCode::Success
65 }
66 Decision::Deny => {
67 println!("DENY");
68 CedarExitCode::AuthorizeDeny
69 }
70 };
71 if ans.diagnostics().errors().peekable().peek().is_some() {
72 println!();
73 for err in ans.diagnostics().errors() {
74 println!("{err}");
75 }
76 }
77 if args.verbose {
78 println!();
79 if ans.diagnostics().reason().peekable().peek().is_none() {
80 println!("note: no policies applied to this request");
81 } else {
82 println!("note: this decision was due to the following policies:");
83 for reason in ans.diagnostics().reason() {
84 println!(" {reason}");
85 }
86 println!();
87 }
88 }
89 status
90 }
91 Err(errs) => {
92 for err in errs {
93 println!("{err:?}");
94 }
95 CedarExitCode::Failure
96 }
97 }
98}
99
100fn execute_request(
102 request: &RequestArgs,
103 policies: &PoliciesArgs,
104 entities_filename: impl AsRef<Path>,
105 schema: &OptionalSchemaArgs,
106 compute_duration: bool,
107) -> Result<Response, Vec<Report>> {
108 let mut errs = vec![];
109 let policies = match policies.get_policy_set() {
110 Ok(pset) => pset,
111 Err(e) => {
112 errs.push(e);
113 PolicySet::new()
114 }
115 };
116 let schema = match schema.get_schema() {
117 Ok(opt) => opt,
118 Err(e) => {
119 errs.push(e);
120 None
121 }
122 };
123 let entities = match load_entities(entities_filename, schema.as_ref()) {
124 Ok(entities) => entities,
125 Err(e) => {
126 errs.push(e);
127 Entities::empty()
128 }
129 };
130 match request.get_request(schema.as_ref()) {
131 Ok(request) if errs.is_empty() => {
132 let authorizer = Authorizer::new();
133 let auth_start = Instant::now();
134 let ans = authorizer.is_authorized(&request, &policies, &entities);
135 let auth_dur = auth_start.elapsed();
136 if compute_duration {
137 println!(
138 "Authorization Time (micro seconds) : {}",
139 auth_dur.as_micros()
140 );
141 }
142 Ok(ans)
143 }
144 Ok(_) => Err(errs),
145 Err(e) => {
146 errs.push(e.wrap_err("failed to parse request"));
147 Err(errs)
148 }
149 }
150}