src/client/http_client.rs: try to login
use an environment var to store passphrase (PBS_PASSWORD)
This commit is contained in:
parent
33d64b81e0
commit
0dffe3f99a
@ -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(¶m, "repository")?;
|
let repo_url = tools::required_string_param(¶m, "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);
|
||||||
|
|
||||||
|
@ -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)?;
|
||||||
|
|
||||||
|
@ -70,7 +70,7 @@ impl Service for ApiService {
|
|||||||
match result {
|
match result {
|
||||||
Ok(res) => Ok::<_, hyper::Error>(res),
|
Ok(res) => Ok::<_, hyper::Error>(res),
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
if let Some(apierr) = err.downcast_ref::<HttpError>() {
|
if let Some(apierr) = err.downcast_ref::<HttpError>() {
|
||||||
let mut resp = Response::new(Body::from(apierr.message.clone()));
|
let mut resp = Response::new(Body::from(apierr.message.clone()));
|
||||||
*resp.status_mut() = apierr.code;
|
*resp.status_mut() = apierr.code;
|
||||||
Ok(resp)
|
Ok(resp)
|
||||||
@ -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)
|
||||||
|
Loading…
Reference in New Issue
Block a user