v_common/module/
ticket.rs1use v_individual_model::onto::datatype::Lang;
2use v_individual_model::onto::individual::Individual;
3use crate::v_api::common_type::ResultCode;
4use chrono::{DateTime, NaiveDateTime, Utc};
5use evmap::ShallowCopy;
6use serde_json::Value;
7use std::hash::{Hash, Hasher};
8use std::mem::ManuallyDrop;
9use std::net::IpAddr;
10
11#[derive(Debug, Clone)]
12pub struct Ticket {
13 pub id: String,
14 pub user_uri: String,
16 pub user_login: String,
18 pub result: ResultCode,
20 pub start_time: i64,
22 pub end_time: i64,
24 pub user_addr: String,
25 pub auth_method: String,
27 pub domain: String,
29 pub initiator: String,
31 pub auth_origin: String,
33}
34
35impl Hash for Ticket {
36 fn hash<H: Hasher>(&self, state: &mut H) {
37 self.id.hash(state);
38 }
39}
40
41impl Eq for Ticket {}
42
43impl PartialEq for Ticket {
44 fn eq(&self, other: &Self) -> bool {
45 self.result == other.result
46 && self.user_uri == other.user_uri
47 && self.id == other.id
48 && self.end_time == other.end_time
49 && self.start_time == other.start_time
50 && self.user_login == other.user_login
51 && self.user_addr == other.user_addr
52 && self.auth_method == other.auth_method
53 && self.domain == other.domain
54 && self.initiator == other.initiator
55 && self.auth_origin == other.auth_origin
56 }
57}
58
59impl ShallowCopy for Ticket {
60 unsafe fn shallow_copy(&self) -> ManuallyDrop<Self> {
61 ManuallyDrop::new(Ticket {
62 id: self.id.clone(),
63 user_uri: self.user_uri.clone(),
64 user_login: self.user_login.clone(),
65 result: self.result,
66 start_time: self.start_time,
67 end_time: self.end_time,
68 user_addr: self.user_addr.clone(),
69 auth_method: self.auth_method.clone(),
70 domain: self.domain.clone(),
71 initiator: self.initiator.clone(),
72 auth_origin: self.auth_origin.clone(),
73 })
74 }
75}
76
77impl Default for Ticket {
78 fn default() -> Self {
79 Ticket {
80 id: String::default(),
81 user_uri: String::default(),
82 user_login: String::default(),
83 result: ResultCode::AuthenticationFailed,
84 start_time: 0,
85 end_time: 0,
86 user_addr: "".to_string(),
87 auth_method: "".to_string(),
88 domain: "".to_string(),
89 initiator: "".to_string(),
90 auth_origin: "".to_string(),
91 }
92 }
93}
94
95impl From<serde_json::Value> for Ticket {
96 fn from(val: Value) -> Self {
97 let mut t = Ticket::default();
98 if let Some(v) = val["id"].as_str() {
99 t.id = v.to_owned();
100 }
101 if let Some(v) = val["user_uri"].as_str() {
102 t.user_uri = v.to_owned();
103 }
104 if let Some(v) = val["user_login"].as_str() {
105 t.user_login = v.to_owned();
106 }
107 if let Some(v) = val["result"].as_i64() {
108 t.result = ResultCode::from_i64(v);
109 }
110 if let Some(v) = val["end_time"].as_i64() {
111 t.end_time = v;
112 }
113 if let Some(v) = val["user_addr"].as_str() {
114 t.user_addr = v.to_owned();
115 }
116 if let Some(v) = val["auth_method"].as_str() {
117 t.auth_method = v.to_owned();
118 }
119 if let Some(v) = val["domain"].as_str() {
120 t.domain = v.to_owned();
121 }
122 if let Some(v) = val["initiator"].as_str() {
123 t.initiator = v.to_owned();
124 }
125 if let Some(v) = val["auth_origin"].as_str() {
126 t.auth_origin = v.to_owned();
127 }
128
129 t
130 }
131}
132
133impl Ticket {
134 pub fn to_individual(&self) -> Individual {
135 let mut ticket_indv = Individual::default();
136
137 ticket_indv.add_string("rdf:type", "ticket:ticket", Lang::none());
138 ticket_indv.set_id(&self.id);
139
140 ticket_indv.add_string("ticket:login", &self.user_login, Lang::none());
141 ticket_indv.add_string("ticket:accessor", &self.user_uri, Lang::none());
142 ticket_indv.add_string("ticket:addr", &self.user_addr, Lang::none());
143
144 let start_time_str = DateTime::<Utc>::from_timestamp(self.start_time, 0).unwrap_or_default().format("%Y-%m-%dT%H:%M:%S%.f").to_string();
145
146 if start_time_str.len() > 28 {
147 ticket_indv.add_string("ticket:when", &start_time_str[0..28], Lang::none());
148 } else {
149 ticket_indv.add_string("ticket:when", &start_time_str, Lang::none());
150 }
151
152 ticket_indv.add_string("ticket:duration", &(self.end_time - self.start_time).to_string(), Lang::none());
153
154 ticket_indv.add_string("ticket:authMethod", &self.auth_method, Lang::none());
156 ticket_indv.add_string("ticket:domain", &self.domain, Lang::none());
157 ticket_indv.add_string("ticket:initiator", &self.initiator, Lang::none());
158 ticket_indv.add_string("ticket:authOrigin", &self.auth_origin, Lang::none());
159
160 ticket_indv
161 }
162
163 pub fn update_from_individual(&mut self, src: &mut Individual) {
164 let when = src.get_first_literal("ticket:when");
165 let duration = src.get_first_literal("ticket:duration").unwrap_or_default().parse::<i32>().unwrap_or_default();
166
167 self.id = src.get_id().to_owned();
168 self.user_uri = src.get_first_literal("ticket:accessor").unwrap_or_default();
169 self.user_login = src.get_first_literal("ticket:login").unwrap_or_default();
170 self.user_addr = src.get_first_literal("ticket:addr").unwrap_or_default();
171
172 self.auth_method = src.get_first_literal("ticket:authMethod").unwrap_or_default();
174 self.domain = src.get_first_literal("ticket:domain").unwrap_or_default();
175 self.initiator = src.get_first_literal("ticket:initiator").unwrap_or_default();
176 self.auth_origin = src.get_first_literal("ticket:authOrigin").unwrap_or_default();
177
178 if self.user_uri.is_empty() {
179 error!("found a session ticket is not complete, the user can not be found. ticket_id={}", self.id);
180 self.user_uri = String::default();
181 return;
182 }
183
184 if !self.user_uri.is_empty() && (when.is_none() || duration < 10) {
185 error!("found a session ticket is not complete, we believe that the user has not been found.");
186 self.user_uri = String::default();
187 return;
188 }
189 let when = when.unwrap();
190
191 if let Ok(t) = NaiveDateTime::parse_from_str(&when, "%Y-%m-%dT%H:%M:%S%.f") {
192 self.start_time = t.and_utc().timestamp();
193 self.end_time = self.start_time + duration as i64;
194 } else {
195 error!("fail parse field [ticket:when] = {}", when);
196 self.user_uri = String::default();
197 }
198 }
199
200 pub fn is_ticket_valid(&self, addr: &Option<IpAddr>, is_check_addr: bool) -> ResultCode {
201 if is_check_addr {
202 if let Some(a) = addr {
203 if self.user_addr != a.to_string() {
204 error!("decline: ticket {}/{} request from {}", self.id, self.user_addr, a.to_string());
205 return ResultCode::TicketExpired;
206 }
207 } else {
208 return ResultCode::TicketExpired;
209 }
210 }
211
212 if self.result != ResultCode::Ok {
213 return self.result;
214 }
215
216 if Utc::now().timestamp() > self.end_time {
217 return ResultCode::TicketExpired;
218 }
219
220 if self.user_uri.is_empty() {
221 return ResultCode::NotReady;
222 }
223
224 ResultCode::Ok
225 }
226}