use std::{path::Path, sync::Arc};
use async_trait::async_trait;
use opcua_crypto::{CertificateStore, PrivateKey, X509};
use opcua_types::{ByteString, Error, StatusCode};
#[async_trait]
pub trait IssuedTokenSource: Send + Sync {
async fn get_issued_token(&self) -> Result<ByteString, Error>;
}
#[async_trait]
impl IssuedTokenSource for ByteString {
async fn get_issued_token(&self) -> Result<ByteString, Error> {
Ok(self.clone())
}
}
#[derive(Clone)]
pub struct IssuedTokenWrapper(pub(crate) Arc<dyn IssuedTokenSource>);
impl IssuedTokenWrapper {
pub fn new(token_source: Arc<dyn IssuedTokenSource>) -> Self {
Self(token_source)
}
pub fn new_source(token_source: impl IssuedTokenSource + 'static) -> Self {
Self(Arc::new(token_source))
}
}
impl std::fmt::Debug for IssuedTokenWrapper {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_tuple("IssuedTokenSource").finish()
}
}
#[derive(Clone)]
pub struct Password(pub String);
impl Password {
pub fn new(password: impl Into<String>) -> Self {
Password(password.into())
}
}
impl<T> From<T> for Password
where
T: Into<String>,
{
fn from(value: T) -> Self {
Password(value.into())
}
}
impl std::fmt::Debug for Password {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_tuple("Password").field(&"*****").finish()
}
}
#[derive(Debug, Clone)]
pub enum IdentityToken {
Anonymous,
UserName(String, Password),
X509(Box<X509>, Box<PrivateKey>),
IssuedToken(IssuedTokenWrapper),
}
impl IdentityToken {
pub fn new_anonymous() -> Self {
IdentityToken::Anonymous
}
pub fn new_user_name(user_name: impl Into<String>, password: impl Into<Password>) -> Self {
IdentityToken::UserName(user_name.into(), password.into())
}
pub fn new_x509(cert: X509, private_key: PrivateKey) -> Self {
IdentityToken::X509(Box::new(cert), Box::new(private_key))
}
pub fn new_x509_path(
cert_path: impl AsRef<Path>,
key_path: impl AsRef<Path>,
) -> Result<Self, Error> {
let cert = CertificateStore::read_cert(cert_path.as_ref())
.map_err(|e| Error::new(StatusCode::Bad, e))?;
let private_key = CertificateStore::read_pkey(key_path.as_ref())
.map_err(|e| Error::new(StatusCode::Bad, e))?;
Ok(IdentityToken::X509(Box::new(cert), Box::new(private_key)))
}
pub fn new_issued_token(token_source: impl IssuedTokenSource + 'static) -> Self {
IdentityToken::IssuedToken(IssuedTokenWrapper::new_source(token_source))
}
pub fn new_issued_token_arc(token_source: Arc<dyn IssuedTokenSource>) -> Self {
IdentityToken::IssuedToken(IssuedTokenWrapper::new(token_source))
}
}