Flex Gateway新着情報
Governance新着情報
Monitoring API ManagerAPI インスタンスとアプリケーション間のコントラクトにより、アプリケーションは SLA 層に基づいてインスタンスにアクセスできます。クライアントアプリケーションは、クライアント ID とクライアントシークレットで構成されるログイン情報を提供してコントラクトを検証できます。PDK コントラクト検証ライブラリでは、クライアントログイン情報を検証してカスタムクライアント ID 適用ポリシーを実装する関数が提供されます。
API インスタンスとアプリケーション間に同時に存在できるコントラクトはコントラクトは 1 つのみです。
| Flex Gateway ポリシー開発キット (PDK) コントラクト検証ライブラリを使用するポリシープロジェクトの例については、 「Client ID Enforcement Policy Example (クライアント ID 適用ポリシーの例)」を参照してください。 |
コントラクト検証ライブラリは、pdk::cors モジュールから使用できます。
このモジュールで提供される ContractValidator は、ClientId オブジェクトと ClientSecret オブジェクトで表されるクライアントログイン情報を検証します。ContractValidator::authenticate() メソッドと ContractValidator::authorize() メソッドを使用して、認証および承認ログイン情報を検証します。
impl ContractValidator {
pub fn authenticate(client_id: &ClientId, client_secret: &ClientSecret) -> Result<ClientData, AuthenticationError>;
pub fn authorize(client_id: &ClientId, client_secret: &ClientSecret) -> Result<ClientData, AuthorizationError>;
}
どちらのメソッドでも、クライアント ID、クライアント名、SLA ID 項目が含まれる ClientData 構造体が返されます。
pub struct ClientData {
pub client_id: String,
pub client_name: String,
pub sla_id: Option<String>,
}
要求からクライアントログイン情報を抽出して要求を認証し、ClientValidation::authenticate() メソッドを呼び出します。pdk::contracts モジュールで提供される basic_auth_credentials() ヘルパー関数は、リクエストヘッダーから基本認証ログイン情報を抽出します。
pub fn basic_auth_credentials(request_headers_state: &RequestHeadersState)
-> Result<(ClientId, ClientSecret), BasicAuthError>;
次のコードスニペットでは、認証要求のシンプルな検索条件が提供されます。
async fn my_authentication_filter(
state: RequestHeadersState,
authentication: Authentication,
validator: &ContractValidator,
) -> Flow<()> {
// Extract credentials
let (client_id, client_secret) = match basic_auth_credentials(&state) {
Ok(credentials) => credentials,
Err(e) => {
logger::info!("Invalid credentials: {e}");
// For simplicity, we are using a user-defined `unathorized_response()`
// helper function for building responses.
return Flow::Break(unauthorized_response("Invalid credentials", 401));
}
};
// Validate authentication
let validation = validator.authenticate(&client_id, &client_secret);
let client_data = match validation {
Ok(client_data) => client_data,
Err(e) => {
logger::info!("Invalid authentication: {e}");
return Flow::Break(unauthorized_response("Invalid authentication", 403));
}
};
// Update the current authentication
if let Some(mut auth) = authentication.authentication() {
auth.client_id = Some(client_data.client_id);
auth.client_name = Some(client_data.client_name);
authentication.set_authentication(Some(&auth));
}
Flow::Continue(())
}
次のコードスニペットでは、承認要求のシンプルな検索条件が提供されます。
async fn my_authorization_filter(
state: RequestHeadersState,
validator: &ContractValidator,
) -> Flow<()> {
// Extract client id with a user defined helper `extract_client_id()` function,
let client_id = match extract_client_id(&state) {
Ok(credentials) => credentials,
Err(e) => {
logger::info!("Invalid credentials: {e}");
// For simplicity, we are using a user-defined `unathorized_response()`
// helper function for building responses.
return Flow::Break(unauthorized_response("Invalid credentials", 401));
}
};
// Validate authorization
let validation = validator.authorize(&client_id);
if let Err(e) = validation {
logger::info!("Invalid authentication: {e}");
return Flow::Break(unauthorized_response("Invalid authentication", 403));
}
Flow::Continue(())
}
ClientId::new() および ClientSecret::new() メソッドを呼び出して、ログイン情報を抽出します。
impl ClientId {
pub fn new(client_id: String) -> Self;
}
impl ClientSecret {
pub fn new(client_secret: String) -> Self;
}
ログイン情報を抽出したら、一連のログイン情報を初期化します。
fn initialize_credentials(raw_client_id: String, raw_client_secret) -> (ClientId, ClientSecret) {
let client_id = ClientId::new(raw_client_id);
let client_secret = ClientSecret::new(raw_client_secret);
(client_id, client_secret)
}
セキュリティ上の理由により、ClientSecret のコンテンツは使用後に削除され、Debug trait に ClientSecret のコンテンツは表示されません。
|
ContractValidator オブジェクトを #[entrypoint] 関数に挿入し、要求検索条件への参照を共有します。
#[entrypoint]
async fn configure(launcher: Launcher, validator: ContractValidator) -> Result<(), LaunchError> {
let filter = on_request(|state, authentication| my_authentication_filter(state, authentication, &validator));
launcher.launch(filter).await?;
OK(())
}
ContractValidator オブジェクトには、コントラクトデータベースのローカルコピーが保持されます。ローカルコピーをポーリングして、コントラクトの有効なコピーを保持する必要があります。ContractValidator::update_contracts() メソッドを呼び出して、ローカルコピーをポーリングします。
impl ContractValidator {
pub async fn update_contracts(&self) -> Result<(), UpdateError>;
}
ContractValidator::update_contracts() メソッドでコントラクトデータベースのポーリング中に接続の問題が発生したことを示すエラーが返された場合、再試行およびエラー処理ヒューリスティックを実装する必要があります。これを行うには、ContractValidator::UPDATE_PERIOD 定数で指定された期間に ContractValidator::update_contracts() を呼び出します。
async fn update_my_contracts(validator: &ContractValidator, clock: Clock) {
// Configure a new timer
let timer = clock.period(ContractValidator::UPDATE_PERIOD);
loop {
// Update result handling should be customized by the programmer
let update_result = validator.update_contracts().await;
// Wait for the next tick
if !timer.next_tick().await {
// If no more ticks are available, finish the task.
return;
}
}
}
コントラクトデータベース初期化期間では、更新期間よりも高い頻度でコントラクトデータベースをポーリングする期間を指定します。ContractValidator::INITIALIZATION_PERIOD では、最初のポーリングに必要な間隔を指定します。
async fn initialize_my_contracts(validator: &ContractValidator, clock: Clock) {
// Configure a new timer
let timer = clock.period(ContractValidator::UPDATE_PERIOD);
loop {
// Update result handling should be customized by the programmer
let update_result = validator.update_contracts().await;
// Wait for the next tick
if !timer.next_tick().await {
// If no more ticks are available, finish the task.
return;
}
}
}
次のスニペットは、初期化と更新のポーリング期間が含まれる完全なコントラクトポーリングタスクを示しています。
async fn update_my_contracts(validator: &ContractValidator, clock: Clock) {
let initialization_timer = clock.period(ContractValidator::INITIALIZATION_PERIOD);
loop {
if validator.update_contracts().await.is_ok() {
logger::info!("Contracts storage initialized.");
break;
}
if !initialization_timer.next_tick().await {
logger::info!("Tick event suspended.");
break;
}
}
let update_timer = initialization_timer
.release()
.period(ContractValidator::UPDATE_PERIOD);
loop {
let _ = validator.update_contracts().await;
if !update_timer.next_tick().await {
logger::info!("Tick event suspended.");
break;
}
logger::info!("Retrying contracts storage initialization.");
}
}
コントラクトデータベースポーリングタスクは Launcher::launch() タスクと同時に実行する必要があるため、 futures クレートの join!() マクロを使用して両方のタスクを結合します。次のスニペットでは、ポーリングと起動が含まれる完全な #[entrypoint] 関数を実装します。
#[entrypoint]
async fn configure(launcher: Launcher, clock: Clock,validator: ContractValidator) -> Result<(), LauncherError> {
let filter = on_request(|state, authentication| my_authentication_filter(state, authentication, &validator));
let (_, launcher_result) = join! {
update_my_contracts(&validator, clock),
launcher.launch(filter),
};
launcher_result
}