use async_trait::async_trait;
use osproto::identity as protocol;
use reqwest::{Client, IntoUrl, Method, RequestBuilder, Url};
use super::internal::Internal;
use super::{IdOrName, Identity, Scope};
use crate::{AuthType, EndpointFilters, Error, InterfaceType, ValidInterfaces};
#[derive(Debug, Clone)]
pub struct Password {
inner: Internal,
}
impl Identity for Password {
fn auth_url(&self) -> &Url {
self.inner.auth_url()
}
}
impl Password {
pub fn new<U, S1, S2, S3>(
auth_url: U,
user_name: S1,
password: S2,
user_domain_name: S3,
) -> Result<Password, Error>
where
U: IntoUrl,
S1: Into<String>,
S2: Into<String>,
S3: Into<String>,
{
Password::new_with_client(
auth_url,
Client::new(),
user_name,
password,
user_domain_name,
)
}
pub fn new_with_client<U, S1, S2, S3>(
auth_url: U,
client: Client,
user_name: S1,
password: S2,
user_domain_name: S3,
) -> Result<Password, Error>
where
U: IntoUrl,
S1: Into<String>,
S2: Into<String>,
S3: Into<String>,
{
let auth_url = auth_url.into_url()?;
let pw = protocol::UserAndPassword {
user: protocol::IdOrName::Name(user_name.into()),
password: password.into(),
domain: Some(protocol::IdOrName::Name(user_domain_name.into())),
};
let body = protocol::AuthRoot {
auth: protocol::Auth {
identity: protocol::Identity::Password(pw),
scope: None,
},
};
Ok(Password {
inner: Internal::new(client, auth_url, body)?,
})
}
#[inline]
pub fn endpoint_filters(&self) -> &EndpointFilters {
&self.inner.filters
}
#[inline]
pub fn endpoint_filters_mut(&mut self) -> &mut EndpointFilters {
&mut self.inner.filters
}
pub fn set_default_endpoint_interface(&mut self, endpoint_interface: InterfaceType) {
self.inner.filters.interfaces = ValidInterfaces::one(endpoint_interface);
}
#[inline]
pub fn set_endpoint_filters(&mut self, filters: EndpointFilters) {
self.inner.filters = filters;
}
#[deprecated(since = "0.3.0", note = "Use set_filters or filters_mut")]
pub fn set_region<S>(&mut self, region: S)
where
S: Into<String>,
{
self.inner.filters.region = Some(region.into());
}
#[inline]
pub fn set_project_scope(&mut self, project: IdOrName, domain: impl Into<Option<IdOrName>>) {
self.set_scope(Scope::Project {
project,
domain: domain.into(),
});
}
#[inline]
pub fn set_scope(&mut self, scope: Scope) {
self.inner.set_scope(scope);
}
#[inline]
pub fn with_default_endpoint_interface(mut self, endpoint_interface: InterfaceType) -> Self {
self.set_default_endpoint_interface(endpoint_interface);
self
}
#[inline]
pub fn with_endpoint_filters(mut self, filters: EndpointFilters) -> Self {
self.inner.filters = filters;
self
}
#[inline]
pub fn with_project_scope(
mut self,
project: IdOrName,
domain: impl Into<Option<IdOrName>>,
) -> Password {
self.set_project_scope(project, domain);
self
}
#[inline]
pub fn with_region<S>(mut self, region: S) -> Self
where
S: Into<String>,
{
self.inner.filters.region = Some(region.into());
self
}
#[inline]
pub fn with_scope(mut self, scope: Scope) -> Self {
self.set_scope(scope);
self
}
#[inline]
pub fn user(&self) -> &IdOrName {
self.inner.user().expect("Password auth without a user")
}
#[inline]
pub fn project(&self) -> Option<&IdOrName> {
self.inner.project()
}
}
#[async_trait]
impl AuthType for Password {
fn default_filters(&self) -> Option<&EndpointFilters> {
Some(&self.inner.filters)
}
async fn request(&self, method: Method, url: Url) -> Result<RequestBuilder, Error> {
self.inner.request(method, url).await
}
async fn get_endpoint(
&self,
service_type: String,
filters: EndpointFilters,
) -> Result<Url, Error> {
self.inner.get_endpoint(service_type, filters).await
}
async fn refresh(&self) -> Result<(), Error> {
self.inner.refresh(true).await
}
}
#[cfg(test)]
pub mod test {
#![allow(unused_results)]
use super::Password;
use crate::identity::{IdOrName, Identity};
#[test]
fn test_identity_new() {
let id = Password::new("http://127.0.0.1:8080/", "admin", "pa$$w0rd", "Default").unwrap();
let e = id.auth_url();
assert_eq!(e.scheme(), "http");
assert_eq!(e.host_str().unwrap(), "127.0.0.1");
assert_eq!(e.port().unwrap(), 8080u16);
assert_eq!(e.path(), "/");
assert_eq!(id.user(), &IdOrName::Name("admin".to_string()));
}
#[test]
fn test_identity_new_invalid() {
Password::new("http://127.0.0.1 8080/", "admin", "pa$$w0rd", "Default")
.err()
.unwrap();
}
#[test]
fn test_identity_create() {
let id = Password::new(
"http://127.0.0.1:8080/identity",
"user",
"pa$$w0rd",
"example.com",
)
.unwrap()
.with_project_scope(
IdOrName::Name("cool project".to_string()),
IdOrName::Name("example.com".to_string()),
);
assert_eq!(id.auth_url().to_string(), "http://127.0.0.1:8080/identity");
assert_eq!(id.user(), &IdOrName::Name("user".to_string()));
assert_eq!(
id.project(),
Some(&IdOrName::Name("cool project".to_string()))
);
assert_eq!(
id.inner.token_endpoint(),
"http://127.0.0.1:8080/identity/v3/auth/tokens"
);
assert_eq!(id.endpoint_filters().region, None);
}
#[test]
fn test_token_endpoint_with_trailing_slash() {
let id = Password::new(
"http://127.0.0.1:8080/identity/",
"user",
"pa$$w0rd",
"example.com",
)
.unwrap()
.with_project_scope(
IdOrName::Name("cool project".to_string()),
IdOrName::Name("example.com".to_string()),
);
assert_eq!(id.auth_url().to_string(), "http://127.0.0.1:8080/identity");
assert_eq!(id.user(), &IdOrName::Name("user".to_string()));
assert_eq!(
id.project(),
Some(&IdOrName::Name("cool project".to_string()))
);
assert_eq!(
id.inner.token_endpoint(),
"http://127.0.0.1:8080/identity/v3/auth/tokens"
);
assert_eq!(id.endpoint_filters().region, None);
}
#[test]
fn test_token_endpoint_with_v3() {
let id = Password::new(
"http://127.0.0.1:8080/identity/v3",
"user",
"pa$$w0rd",
"example.com",
)
.unwrap()
.with_project_scope(
IdOrName::Name("cool project".to_string()),
IdOrName::Name("example.com".to_string()),
);
assert_eq!(
id.auth_url().to_string(),
"http://127.0.0.1:8080/identity/v3"
);
assert_eq!(id.user(), &IdOrName::Name("user".to_string()));
assert_eq!(
id.project(),
Some(&IdOrName::Name("cool project".to_string()))
);
assert_eq!(
id.inner.token_endpoint(),
"http://127.0.0.1:8080/identity/v3/auth/tokens"
);
assert_eq!(id.endpoint_filters().region, None);
}
#[test]
fn test_token_endpoint_with_trailing_slash_v3() {
let id = Password::new(
"http://127.0.0.1:8080/identity/v3/",
"user",
"pa$$w0rd",
"example.com",
)
.unwrap()
.with_project_scope(
IdOrName::Name("cool project".to_string()),
IdOrName::Name("example.com".to_string()),
);
assert_eq!(
id.auth_url().to_string(),
"http://127.0.0.1:8080/identity/v3"
);
assert_eq!(id.user(), &IdOrName::Name("user".to_string()));
assert_eq!(
id.project(),
Some(&IdOrName::Name("cool project".to_string()))
);
assert_eq!(
id.inner.token_endpoint(),
"http://127.0.0.1:8080/identity/v3/auth/tokens"
);
assert_eq!(id.endpoint_filters().region, None);
}
}