src/client/http_client.rs: try to login

use an environment var to store passphrase (PBS_PASSWORD)
This commit is contained in:
Dietmar Maurer 2019-02-13 14:31:43 +01:00
parent 33d64b81e0
commit 0dffe3f99a
3 changed files with 50 additions and 4 deletions

View File

@ -53,7 +53,7 @@ impl BackupRepository {
fn backup_directory(repo: &BackupRepository, body: Body, archive_name: &str) -> Result<(), Error> { fn backup_directory(repo: &BackupRepository, body: Body, archive_name: &str) -> Result<(), Error> {
let client = HttpClient::new(&repo.host); let client = HttpClient::new(&repo.host, &repo.user);
let epoch = std::time::SystemTime::now().duration_since( let epoch = std::time::SystemTime::now().duration_since(
std::time::SystemTime::UNIX_EPOCH)?.as_secs(); std::time::SystemTime::UNIX_EPOCH)?.as_secs();
@ -107,7 +107,7 @@ fn list_backups(
let repo_url = tools::required_string_param(&param, "repository")?; let repo_url = tools::required_string_param(&param, "repository")?;
let repo = BackupRepository::parse(repo_url)?; let repo = BackupRepository::parse(repo_url)?;
let client = HttpClient::new(&repo.host); let client = HttpClient::new(&repo.host, &repo.user);
let path = format!("api2/json/admin/datastore/{}/backups", repo.store); let path = format!("api2/json/admin/datastore/{}/backups", repo.store);

View File

@ -9,16 +9,19 @@ use http::Request;
use futures::stream::Stream; use futures::stream::Stream;
use serde_json::{Value}; use serde_json::{Value};
use url::percent_encoding::{percent_encode, DEFAULT_ENCODE_SET};
pub struct HttpClient { pub struct HttpClient {
username: String,
server: String, server: String,
} }
impl HttpClient { impl HttpClient {
pub fn new(server: &str) -> Self { pub fn new(server: &str, username: &str) -> Self {
Self { Self {
server: String::from(server), server: String::from(server),
username: String::from(username),
} }
} }
@ -77,23 +80,64 @@ impl HttpClient {
let url: Uri = format!("https://{}:8007/{}", self.server, path).parse()?; let url: Uri = format!("https://{}:8007/{}", self.server, path).parse()?;
let ticket = self.login()?;
let enc_ticket = percent_encode(ticket.as_bytes(), DEFAULT_ENCODE_SET).to_string();
let request = Request::builder() let request = Request::builder()
.method("GET") .method("GET")
.uri(url) .uri(url)
.header("User-Agent", "proxmox-backup-client/1.0") .header("User-Agent", "proxmox-backup-client/1.0")
.header("Cookie", format!("PBSAuthCookie={}", enc_ticket))
.body(Body::empty())?; .body(Body::empty())?;
Self::run_request(request) Self::run_request(request)
} }
fn login(&self) -> Result<String, Error> {
let url: Uri = format!("https://{}:8007/{}", self.server, "/api2/json/access/ticket").parse()?;
let password = match std::env::var("PBS_PASSWORD") {
Ok(p) => p,
Err(err) => bail!("missing passphrase - {}", err),
};
let query = url::form_urlencoded::Serializer::new(String::new())
.append_pair("username", &self.username)
.append_pair("password", &password)
.finish();
let request = Request::builder()
.method("POST")
.uri(url)
.header("User-Agent", "proxmox-backup-client/1.0")
.header("Content-Type", "application/x-www-form-urlencoded")
.body(Body::from(query))?;
let auth_res = Self::run_request(request)?;
let ticket = match auth_res["data"]["ticket"].as_str() {
Some(t) => t,
None => bail!("got unexpected respose for login request."),
};
Ok(ticket.to_owned())
}
pub fn upload(&self, content_type: &str, body: Body, path: &str) -> Result<Value, Error> { pub fn upload(&self, content_type: &str, body: Body, path: &str) -> Result<Value, Error> {
let url: Uri = format!("https://{}:8007/{}", self.server, path).parse()?; let url: Uri = format!("https://{}:8007/{}", self.server, path).parse()?;
let ticket = self.login()?;
let enc_ticket = percent_encode(ticket.as_bytes(), DEFAULT_ENCODE_SET).to_string();
let request = Request::builder() let request = Request::builder()
.method("POST") .method("POST")
.uri(url) .uri(url)
.header("User-Agent", "proxmox-backup-client/1.0") .header("User-Agent", "proxmox-backup-client/1.0")
.header("Cookie", format!("PBSAuthCookie={}", enc_ticket))
.header("Content-Type", content_type) .header("Content-Type", content_type)
.body(body)?; .body(body)?;

View File

@ -458,6 +458,8 @@ pub fn handle_request(api: Arc<ApiConfig>, req: Request<Body>) -> BoxFut {
if let Some(_username) = rpcenv.get_user() { if let Some(_username) = rpcenv.get_user() {
// fixme: check permissions // fixme: check permissions
} else { } else {
println!("Abort UNAUTHORIZED API REQUEST");
// always delay unauthorized calls by 3 seconds (from start of request) // always delay unauthorized calls by 3 seconds (from start of request)
let resp = (formatter.format_error)(http_err!(UNAUTHORIZED, "permission check failed.".into())); let resp = (formatter.format_error)(http_err!(UNAUTHORIZED, "permission check failed.".into()));
let delayed_response = tokio::timer::Delay::new(delay_unauth_time) let delayed_response = tokio::timer::Delay::new(delay_unauth_time)