Forked from an inaccessible project.
-
Nik | Klampfradler authoredNik | Klampfradler authored
oauth.rs 5.57 KiB
/* Copyright 2021 Dominik George <dominik.george@teckids.org>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
use crate::config::{
get_or_error,
get_optional
};
use config::Config;
use oauth2::{
AuthUrl,
ClientId,
ClientSecret,
RequestTokenError,
ResourceOwnerUsername,
ResourceOwnerPassword,
Scope,
TokenResponse,
TokenUrl
};
use oauth2::basic::{
BasicClient,
BasicTokenResponse
};
use oauth2::reqwest::http_client;
use std::error;
use serde::Deserialize;
use reqwest;
use serde_json;
use jq_rs;
fn full_key(parts: Vec<&str>) -> String {
parts.join(".")
}
fn get_client<E: Copy>(conf: &Config, prefix: &str, error_value: E) -> Result<BasicClient, E> {
let client_id = ClientId::new(get_or_error(&conf, &full_key(vec![prefix, "client_id"]), error_value)?);
let client_secret = match get_optional(&conf, &full_key(vec![prefix, "client_secret"])) {
Some(v) => Some(ClientSecret::new(v)),
None => None,
};
let auth_url = match AuthUrl::new(get_or_error(&conf, &full_key(vec![prefix, "auth_url"]), error_value)?) {
Ok(u) => u,
_ => {
error!("Could not parse authorization URL");
return Err(error_value);
},
};
let token_url = match get_optional(&conf, &full_key(vec![prefix, "token_url"])) {
Some(v) => match TokenUrl::new(v) {
Ok(u) => Some(u),
Err(_) => {
error!("Could not parse token URL");
return Err(error_value);
}
},
None => None,
};
let client = BasicClient::new(client_id, client_secret, auth_url, token_url);
return Ok(client);
}
pub fn get_access_token_client<E: Copy>(conf: &Config, prefix: &str, error_value: E, unauth_value: E) -> Result<BasicTokenResponse, E> {
let scopes: Vec<String> = match get_optional(&conf, &full_key(vec![prefix, "scopes"])) {
Some(v) => v,
None => vec![]
};
let client = get_client(conf, prefix, error_value)?;
let mut request = client.exchange_client_credentials();
for scope in scopes {
request = request.add_scope(Scope::new(scope.to_string()));
}
let result = request.request(http_client);
match result {
Ok(t) => Ok(t),
Err(e) => match e {
RequestTokenError::ServerResponse(t) => {
error!("Authorization server returned error: {}", t);
return Err(unauth_value);
},
_ => {
error!("Error fetchin access token: {}", e);
return Err(error_value);
},
},
}
}
pub fn get_access_token_password<E: Copy>(conf: &Config, prefix: &str, username: String, password: String, error_value: E, unauth_value: E) -> Result<BasicTokenResponse, E> {
let scopes: Vec<String> = match get_optional(&conf, &full_key(vec![prefix, "scopes"])) {
Some(v) => v,
None => vec![]
};
let res_username = ResourceOwnerUsername::new(username);
let res_password = ResourceOwnerPassword::new(password);
let client = get_client(conf, prefix, error_value)?;
let mut request = client.exchange_password(&res_username, &res_password);
for scope in scopes {
request = request.add_scope(Scope::new(scope.to_string()));
}
let result = request.request(http_client);
match result {
Ok(t) => Ok(t),
Err(e) => match e {
RequestTokenError::ServerResponse(t) => {
error!("Authorization server returned error: {}", t);
return Err(unauth_value);
},
_ => {
error!("Error fetchin access token: {}", e);
return Err(error_value);
},
},
}
}
fn get_data(conf: &Config, prefix: &str, endpoint: &str, param: String, token: &BasicTokenResponse) -> Result<String, Box<dyn error::Error>> {
let access_token = token.access_token().secret();
let mut endpoint_url: String = get_or_error(&conf, &full_key(vec![prefix, "urls", endpoint]), "")?;
endpoint_url = endpoint_url.replace("{}", ¶m);
debug!("Loading text data from {}", endpoint_url);
let client = reqwest::blocking::Client::new();
Ok(client
.get(&endpoint_url)
.header(reqwest::header::AUTHORIZATION, format!("Bearer {}", access_token))
.send()?
.text()?)
}
pub fn get_data_jq<T: for<'de> Deserialize<'de>>(conf: &Config, prefix: &str, endpoint: &str, param: String, token: &BasicTokenResponse, multi: bool) -> Result<T, Box<dyn error::Error>> {
let res: Option<String> = get_optional(&conf, &full_key(vec![prefix, "maps", endpoint]));
let jq_code = match res {
Some(s) => match multi {
true => "map(".to_string() + &s + ")",
false => s
},
None => ".".to_string()
};
let mut jq_prog = jq_rs::compile(&jq_code)?;
let data_raw = get_data(&conf, prefix, endpoint, param, token)?;
let data_trans = jq_prog.run(&data_raw)?;
Ok(serde_json::from_str(&data_trans)?)
}