1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
//! Extracting information from authentication exchanges
//!
//! For the server side of an authentication it is usually required to be able to extract some
//! meaningful information from the authentication, e.g. the user that was just authenticated.
//!
//! [`Validation`] provide a facility to enable exactly that, by enabling the user-provided
//! callback to send data to the protocol implementation (i.e. the code calling `Session::step`
//! or `step64`) while having access to the entire context of the authentication exchange.
//!
//! The type of this data can be freely selected by the protocol implementation.
//!
//! To do so a protocol implementation needs to implement the `Validation` trait on a marker type
//! and binds it on the `SASLServer` used. This marker type and the associated Value must both be
//! visible to the user providing the callback.
//!
//! ```
//! # #[cfg(all(not(miri), feature = "provider"))]
//! # {
//! # use std::convert::Infallible;
//! use std::sync::Arc;
//! use rsasl::prelude::*;
//! use rsasl::validate::Validation;
//!
//! pub struct MyDataType {
//! pub username: String,
//! pub authzid: Option<String>
//! }
//!
//! pub struct MyValidation;
//! impl Validation for MyValidation {
//! // The Value can be any type that's `Sized` and `'static`.
//! type Value = MyDataType;
//! }
//!
//! fn do_auth(config: Arc<SASLConfig>, selected: &Mechname) {
//! let sasl = SASLServer::<MyValidation>::new(config);
//!
//! let mut session = sasl.start_suggested(selected).unwrap();
//! // do authentication stepping and so on
//!
//! // Since `SASLServer` was constructed with `MyValidation`, calling `validation()` returns
//! // `Option<MyDataType>`
//! let my_data_type: MyDataType = session.validation().expect("user callback didn't validate");
//! }
//! # }
//! ```
use crateBox;
use crate;
use TypeId;
use Error;
/// Marker trait to define the type returned by `validation`
///
/// This trait is usually implemented on some zero-sized type (ZST):
/// ```rust
/// # use rsasl::prelude::Validation;
/// pub struct MyCustomValidation;
/// impl Validation for MyCustomValidation {
/// type Value = u32;
/// }
/// ```
///
/// However, it can also be implemented on any other type, which is useful if said type is the
/// one to be returned from the Validation:
/// ```rust
/// # use rsasl::prelude::Validation;
/// pub struct MyLoginUserType {
/// username: String,
/// }
/// impl Validation for MyLoginUserType {
/// type Value = Self;
/// }
/// ```
///
/// Often it is most useful to make `Value` a `Result` with the `Err` type changing the
/// authentication error that will be indicated to the client by the protocol implementation:
///
/// ```rust
/// # use rsasl::prelude::Validation;
/// pub struct MyCustomValidation;
/// pub struct Success { /* Fill with user data to be used on successful authentication */ }
/// pub enum Error {
/// // If this is returned from Validation, an "invalid credentials" type of error is returned
/// // (e.g. SMTP 535, XMPP 'not-authorized', …)
/// CredentialsInvalid,
///
/// // Return a "not permitted" type of error (e.g. SMTP 550, XMPP 'account-disabled' or
/// // 'credentials-expired'
/// LoginNotPermitted,
///
/// // Return a "temporary failure" type of error (e.g. SMTP 454, XMPP 'temporary-auth-failure')
/// TemporaryFailure {
/// reason: String,
/// }
///
/// // etc.
/// }
/// impl Validation for MyCustomValidation {
/// type Value = Result<Success, Error>;
/// }
/// ```
///
/// This way the user callback can implement all of the business logic of deciding on the error
/// type to be indicated to the client, making the protocol implementation more abstract and
/// reusable.
/// A default "Validation" that expects no data to be set.
///
/// You will rarely use this type explicitly as it's rather useless.
;
/// A type-erased validation request from a protocol crate
///
/// `Validate` behave very similar to the usual `Request`, but can only store 'Sized' values.
/// Additionally their data types are defined by the protocol implementation instead of the
/// mechanism.
;