support arbitrary SASL mechanisms
This commit is contained in:
parent
2722e1ebf3
commit
26d2710c1f
4 changed files with 42 additions and 15 deletions
|
@ -4,15 +4,17 @@ use xmpp::jid::Jid;
|
||||||
use xmpp::client::ClientBuilder;
|
use xmpp::client::ClientBuilder;
|
||||||
use xmpp::plugins::messaging::{MessagingPlugin, MessageEvent};
|
use xmpp::plugins::messaging::{MessagingPlugin, MessageEvent};
|
||||||
use xmpp::plugins::presence::{PresencePlugin, Show};
|
use xmpp::plugins::presence::{PresencePlugin, Show};
|
||||||
|
use xmpp::sasl::mechanisms::Plain;
|
||||||
|
|
||||||
use std::env;
|
use std::env;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let jid: Jid = env::var("JID").unwrap().parse().unwrap();
|
let jid: Jid = env::var("JID").unwrap().parse().unwrap();
|
||||||
let mut client = ClientBuilder::new(jid).connect().unwrap();
|
let mut client = ClientBuilder::new(jid.clone()).connect().unwrap();
|
||||||
client.register_plugin(MessagingPlugin::new());
|
client.register_plugin(MessagingPlugin::new());
|
||||||
client.register_plugin(PresencePlugin::new());
|
client.register_plugin(PresencePlugin::new());
|
||||||
client.connect_plain(&env::var("PASS").unwrap()).unwrap();
|
let pass = env::var("PASS").unwrap();
|
||||||
|
client.connect(&mut Plain::new(jid.node.clone().expect("JID requires a node"), pass)).unwrap();
|
||||||
client.plugin::<PresencePlugin>().set_presence(Show::Available, None).unwrap();
|
client.plugin::<PresencePlugin>().set_presence(Show::Available, None).unwrap();
|
||||||
loop {
|
loop {
|
||||||
let event = client.next_event().unwrap();
|
let event = client.next_event().unwrap();
|
||||||
|
|
|
@ -6,7 +6,6 @@ use plugin::{Plugin, PluginProxyBinding};
|
||||||
use event::AbstractEvent;
|
use event::AbstractEvent;
|
||||||
use connection::{Connection, C2S};
|
use connection::{Connection, C2S};
|
||||||
use sasl::SaslMechanism;
|
use sasl::SaslMechanism;
|
||||||
use sasl::mechanisms::Plain as SaslPlain;
|
|
||||||
|
|
||||||
use base64;
|
use base64;
|
||||||
|
|
||||||
|
@ -122,8 +121,8 @@ impl Client {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Connects using SASL plain authentication.
|
/// Connects using the specified SASL mechanism.
|
||||||
pub fn connect_plain(&mut self, password: &str) -> Result<(), Error> {
|
pub fn connect<S: SaslMechanism>(&mut self, mechanism: &mut S) -> Result<(), Error> {
|
||||||
// TODO: this is very ugly
|
// TODO: this is very ugly
|
||||||
loop {
|
loop {
|
||||||
let e = self.transport.read_event().unwrap();
|
let e = self.transport.read_event().unwrap();
|
||||||
|
@ -150,19 +149,36 @@ impl Client {
|
||||||
self.transport.write_element(&elem)?;
|
self.transport.write_element(&elem)?;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
let name = self.jid.node.clone().expect("JID has no node");
|
let auth = mechanism.initial();
|
||||||
let mut plain = SaslPlain::new(name, password.to_owned());
|
let mut elem = Element::builder("auth")
|
||||||
let auth = plain.initial();
|
|
||||||
let elem = Element::builder("auth")
|
|
||||||
.text(base64::encode(&auth))
|
|
||||||
.ns(ns::SASL)
|
.ns(ns::SASL)
|
||||||
.attr("mechanism", "PLAIN")
|
.attr("mechanism", "PLAIN")
|
||||||
.build();
|
.build();
|
||||||
self.transport.write_element(&elem)?;
|
if !auth.is_empty() {
|
||||||
did_sasl = true;
|
elem.append_text_node(base64::encode(&auth));
|
||||||
}
|
}
|
||||||
|
self.transport.write_element(&elem)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if n.is("challenge", ns::SASL) {
|
||||||
|
let text = n.text();
|
||||||
|
let challenge = if text == "" {
|
||||||
|
Vec::new()
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
base64::decode(&text)?
|
||||||
|
};
|
||||||
|
let response = mechanism.response(&challenge);
|
||||||
|
let mut elem = Element::builder("response")
|
||||||
|
.ns(ns::SASL)
|
||||||
|
.build();
|
||||||
|
if !response.is_empty() {
|
||||||
|
elem.append_text_node(base64::encode(&response));
|
||||||
|
}
|
||||||
|
self.transport.write_element(&elem)?;
|
||||||
}
|
}
|
||||||
else if n.is("success", ns::SASL) {
|
else if n.is("success", ns::SASL) {
|
||||||
|
did_sasl = true;
|
||||||
self.transport.reset_stream();
|
self.transport.reset_stream();
|
||||||
C2S::init(&mut self.transport, &self.jid.domain, "after_sasl")?;
|
C2S::init(&mut self.transport, &self.jid.domain, "after_sasl")?;
|
||||||
loop {
|
loop {
|
||||||
|
|
|
@ -12,6 +12,8 @@ use xml::writer::Error as EmitterError;
|
||||||
|
|
||||||
use minidom::Error as MinidomError;
|
use minidom::Error as MinidomError;
|
||||||
|
|
||||||
|
use base64::Base64Error;
|
||||||
|
|
||||||
/// An error which wraps a bunch of errors from different crates and the stdlib.
|
/// An error which wraps a bunch of errors from different crates and the stdlib.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
|
@ -21,6 +23,7 @@ pub enum Error {
|
||||||
HandshakeError(HandshakeError<TcpStream>),
|
HandshakeError(HandshakeError<TcpStream>),
|
||||||
OpenSslErrorStack(ErrorStack),
|
OpenSslErrorStack(ErrorStack),
|
||||||
MinidomError(MinidomError),
|
MinidomError(MinidomError),
|
||||||
|
Base64Error(Base64Error),
|
||||||
StreamError,
|
StreamError,
|
||||||
EndOfDocument,
|
EndOfDocument,
|
||||||
}
|
}
|
||||||
|
@ -60,3 +63,9 @@ impl From<MinidomError> for Error {
|
||||||
Error::MinidomError(err)
|
Error::MinidomError(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<Base64Error> for Error {
|
||||||
|
fn from(err: Base64Error) -> Error {
|
||||||
|
Error::Base64Error(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -10,7 +10,7 @@ pub trait SaslMechanism {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a response to the SASL challenge.
|
/// Creates a response to the SASL challenge.
|
||||||
fn respond(&mut self, _challenge: &[u8]) -> Vec<u8> {
|
fn response(&mut self, _challenge: &[u8]) -> Vec<u8> {
|
||||||
Vec::new()
|
Vec::new()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue