1use super::extract::{
2 optional_endpoint, optional_request_id, required_str, session_indexes_from_value,
3};
4use super::identifiers::{MessageId, SessionIndex};
5use super::subject::NameId;
6use super::EndpointUrl;
7use crate::config::EntityId;
8use crate::constants::status_code;
9use crate::error::SamlError;
10use crate::raw::FlowResult;
11
12#[derive(Debug, Clone, PartialEq, Eq)]
14pub struct LogoutSubject {
15 name_id: NameId,
16 session_indexes: Vec<SessionIndex>,
17}
18
19impl LogoutSubject {
20 pub fn new(name_id: NameId, session_indexes: Vec<SessionIndex>) -> Self {
22 Self {
23 name_id,
24 session_indexes,
25 }
26 }
27
28 pub fn from_name_id(name_id: NameId) -> Self {
30 Self::new(name_id, Vec::new())
31 }
32
33 pub fn with_session_index(name_id: NameId, session_index: SessionIndex) -> Self {
35 Self::new(name_id, vec![session_index])
36 }
37
38 pub fn name_id(&self) -> &NameId {
40 &self.name_id
41 }
42
43 pub fn session_index(&self) -> Option<&SessionIndex> {
45 self.session_indexes.first()
46 }
47
48 pub fn session_indexes(&self) -> &[SessionIndex] {
50 &self.session_indexes
51 }
52}
53
54#[derive(Debug, Clone)]
56pub struct LogoutRequest {
57 id: MessageId,
58 issuer: EntityId,
59 name_id: Option<NameId>,
60 session_indexes: Vec<SessionIndex>,
61 destination: Option<EndpointUrl>,
62 raw_flow: FlowResult,
63}
64
65impl LogoutRequest {
66 pub fn id(&self) -> &MessageId {
68 &self.id
69 }
70
71 pub fn issuer(&self) -> &EntityId {
73 &self.issuer
74 }
75
76 pub fn name_id(&self) -> Option<&NameId> {
78 self.name_id.as_ref()
79 }
80
81 pub fn session_indexes(&self) -> &[SessionIndex] {
83 &self.session_indexes
84 }
85
86 pub fn destination(&self) -> Option<&EndpointUrl> {
88 self.destination.as_ref()
89 }
90
91 pub fn raw_flow(&self) -> &FlowResult {
93 &self.raw_flow
94 }
95}
96
97impl TryFrom<FlowResult> for LogoutRequest {
98 type Error = SamlError;
99
100 fn try_from(raw_flow: FlowResult) -> Result<Self, Self::Error> {
101 let id = MessageId::try_new(required_str(&raw_flow.extract, "request.id")?)?;
102 let issuer = EntityId::try_new(required_str(&raw_flow.extract, "issuer")?)?;
103 let name_id = raw_flow
104 .extract
105 .get_str("nameID")
106 .map(|value| NameId::new(value, None));
107 let session_indexes = session_indexes_from_value(raw_flow.extract.get("sessionIndex"))?;
108 let destination = optional_endpoint(&raw_flow.extract, "request.destination")?;
109 Ok(Self {
110 id,
111 issuer,
112 name_id,
113 session_indexes,
114 destination,
115 raw_flow,
116 })
117 }
118}
119
120#[derive(Debug, Clone)]
122pub struct LogoutResponse {
123 id: MessageId,
124 issuer: EntityId,
125 in_response_to: Option<MessageId>,
126 destination: Option<EndpointUrl>,
127 raw_flow: FlowResult,
128}
129
130impl LogoutResponse {
131 pub fn id(&self) -> &MessageId {
133 &self.id
134 }
135
136 pub fn issuer(&self) -> &EntityId {
138 &self.issuer
139 }
140
141 pub fn in_response_to(&self) -> Option<&MessageId> {
143 self.in_response_to.as_ref()
144 }
145
146 pub fn destination(&self) -> Option<&EndpointUrl> {
148 self.destination.as_ref()
149 }
150
151 pub fn raw_flow(&self) -> &FlowResult {
153 &self.raw_flow
154 }
155}
156
157impl TryFrom<FlowResult> for LogoutResponse {
158 type Error = SamlError;
159
160 fn try_from(raw_flow: FlowResult) -> Result<Self, Self::Error> {
161 let id = MessageId::try_new(required_str(&raw_flow.extract, "response.id")?)?;
162 let issuer = EntityId::try_new(required_str(&raw_flow.extract, "issuer")?)?;
163 let in_response_to = optional_request_id(&raw_flow.extract, "response.inResponseTo")?;
164 let destination = optional_endpoint(&raw_flow.extract, "response.destination")?;
165 Ok(Self {
166 id,
167 issuer,
168 in_response_to,
169 destination,
170 raw_flow,
171 })
172 }
173}
174
175#[derive(Debug, Clone)]
177pub struct LogoutCompleted {
178 peer_entity_id: EntityId,
179 response: Option<LogoutResponse>,
180}
181
182impl PartialEq for LogoutCompleted {
183 fn eq(&self, other: &Self) -> bool {
184 self.peer_entity_id == other.peer_entity_id
185 }
186}
187
188impl Eq for LogoutCompleted {}
189
190impl LogoutCompleted {
191 pub fn new(peer_entity_id: EntityId) -> Self {
193 Self {
194 peer_entity_id,
195 response: None,
196 }
197 }
198
199 pub fn from_response(peer_entity_id: EntityId, response: LogoutResponse) -> Self {
201 Self {
202 peer_entity_id,
203 response: Some(response),
204 }
205 }
206
207 pub fn peer_entity_id(&self) -> &EntityId {
209 &self.peer_entity_id
210 }
211
212 pub fn response(&self) -> Option<&LogoutResponse> {
214 self.response.as_ref()
215 }
216
217 pub fn status(&self) -> Option<&str> {
219 self.response.as_ref().map(|_| status_code::SUCCESS)
220 }
221
222 pub fn raw_flow(&self) -> Option<&FlowResult> {
224 self.response.as_ref().map(LogoutResponse::raw_flow)
225 }
226}