-
Notifications
You must be signed in to change notification settings - Fork 10
Expand file tree
/
Copy pathmetadata.rs
More file actions
162 lines (144 loc) · 5.64 KB
/
metadata.rs
File metadata and controls
162 lines (144 loc) · 5.64 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
use crate::openapi::AUTHZEN_TAG;
use axum::{
body::Body,
extract::Request,
response::{IntoResponse, Json, Response},
};
use http::StatusCode;
use serde::{Deserialize, Serialize};
use utoipa::ToSchema;
/// AuthZen PDP Metadata Response - provides information about the PDP capabilities
#[derive(Debug, Serialize, Deserialize, ToSchema, Clone, PartialEq)]
pub struct AuthZenMetadataResponse {
pub policy_decision_point: String,
pub access_evaluation_endpoint: String,
pub access_evaluations_endpoint: String,
pub search_subject_endpoint: String,
pub search_action_endpoint: String,
pub search_resource_endpoint: String,
}
#[utoipa::path(
get,
path = "/.well-known/authzen-configuration",
tag = AUTHZEN_TAG,
responses(
(status = 200, description = "PDP metadata retrieved successfully", body = AuthZenMetadataResponse),
(status = 401, description = "Unauthorized"),
)
)]
pub async fn authzen_metadata_handler(request: Request<Body>) -> Response {
// Get the base URL from the request
// Prioritize Host header for authority, then URI authority, then default.
// Scheme is from URI or defaults to "http".
let uri_parts = request.uri().clone().into_parts();
let scheme = uri_parts
.scheme
.as_ref()
.map(|s| s.to_string())
.unwrap_or_else(|| "http".to_string());
let authority = request
.headers()
.get(http::header::HOST)
.and_then(|host_header| host_header.to_str().ok())
.map(|host_str| host_str.to_string())
.or_else(|| uri_parts.authority.as_ref().map(|auth| auth.to_string()))
.unwrap_or_else(|| "localhost:7766".to_string());
let base_url = format!("{scheme}://{authority}");
let metadata = AuthZenMetadataResponse {
policy_decision_point: base_url.clone(),
access_evaluation_endpoint: format!("{base_url}/access/v1/evaluation"),
access_evaluations_endpoint: format!("{base_url}/access/v1/evaluations"),
search_subject_endpoint: format!("{base_url}/access/v1/search/subject"),
search_resource_endpoint: format!("{base_url}/access/v1/search/resource"),
search_action_endpoint: format!("{base_url}/access/v1/search/action"),
};
(StatusCode::OK, Json(metadata)).into_response()
}
#[cfg(test)]
mod tests {
use super::*;
use crate::test_utils::TestFixture;
use axum::body::Body;
use http::{Request as HttpRequest, StatusCode, Uri};
#[tokio::test]
async fn test_authzen_metadata_handler() {
// Setup test fixture
let fixture = TestFixture::new().await;
// Send request to the metadata endpoint
let response = fixture.get("/.well-known/authzen-configuration").await;
// Verify response status
response.assert_status(StatusCode::OK);
// Parse the response body
let metadata: AuthZenMetadataResponse = response.json_as();
// Verify the response contains expected fields
assert_eq!(metadata.policy_decision_point, "http://localhost:7766");
assert_eq!(
metadata.access_evaluation_endpoint,
"http://localhost:7766/access/v1/evaluation"
);
assert_eq!(
metadata.access_evaluations_endpoint,
"http://localhost:7766/access/v1/evaluations"
);
assert_eq!(
metadata.search_subject_endpoint,
"http://localhost:7766/access/v1/search/subject"
);
assert_eq!(
metadata.search_action_endpoint,
"http://localhost:7766/access/v1/search/action"
);
assert_eq!(
metadata.search_resource_endpoint,
"http://localhost:7766/access/v1/search/resource"
);
}
#[tokio::test]
async fn test_authzen_metadata_handler_with_custom_host() {
// Setup test fixture
let fixture = TestFixture::new().await;
// Create a custom URI with a specific scheme, host and port
let uri_string = "https://custom-host.example.com:8443/.well-known/authzen-configuration";
let uri = Uri::try_from(uri_string).expect("Failed to create URI");
// Build a request manually
let request = HttpRequest::builder()
.uri(uri)
.method("GET")
.header(
"Authorization",
format!("Bearer {}", fixture.config.api_key),
)
.header("Content-Type", "application/json")
.body(Body::empty())
.expect("Failed to build request");
// Send the request
let response = fixture.send(request).await;
// Verify response status
response.assert_status(StatusCode::OK);
// Parse the response body
let metadata: AuthZenMetadataResponse = response.json_as();
// Verify the response contains the custom scheme, host and port
let expected_base = "https://custom-host.example.com:8443";
assert_eq!(metadata.policy_decision_point, expected_base);
assert_eq!(
metadata.access_evaluation_endpoint,
format!("{expected_base}/access/v1/evaluation")
);
assert_eq!(
metadata.access_evaluations_endpoint,
format!("{expected_base}/access/v1/evaluations")
);
assert_eq!(
metadata.search_subject_endpoint,
format!("{expected_base}/access/v1/search/subject")
);
assert_eq!(
metadata.search_action_endpoint,
format!("{expected_base}/access/v1/search/action")
);
assert_eq!(
metadata.search_resource_endpoint,
format!("{expected_base}/access/v1/search/resource")
);
}
}