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
use crate::authorization_code_flow::AuthorizationCodeFlow;
use azure_core::error::{Error, ErrorKind};
use log::debug;
use oauth2::{AuthorizationCode, CsrfToken};
use std::io::{BufRead, BufReader, Write};
use std::net::TcpListener;
use url::Url;
pub fn naive_redirect_server(
auth_obj: &AuthorizationCodeFlow,
port: u32,
) -> azure_core::Result<AuthorizationCode> {
let listener = TcpListener::bind(format!("127.0.0.1:{}", port)).unwrap();
if let Some(mut stream) = listener.incoming().flatten().next() {
let mut reader = BufReader::new(&stream);
let mut request_line = String::new();
reader.read_line(&mut request_line).unwrap();
let redirect_url = match request_line.split_whitespace().nth(1) {
Some(redirect_url) => redirect_url,
None => {
return Err(Error::with_message(ErrorKind::Credential, || {
format!("unexpected redirect url: {}", request_line)
}))
}
};
let url = Url::parse(&("http://localhost".to_string() + redirect_url)).unwrap();
debug!("url == {}", url);
let code = match url.query_pairs().find(|(key, _)| key == "code") {
Some((_, value)) => AuthorizationCode::new(value.into_owned()),
None => {
return Err(Error::message(
ErrorKind::Credential,
"query pair not found: code",
))
}
};
let state = match url.query_pairs().find(|(key, _)| key == "state") {
Some((_, value)) => CsrfToken::new(value.into_owned()),
None => {
return Err(Error::message(
ErrorKind::Credential,
"query pair not found: state",
))
}
};
if state.secret() != auth_obj.csrf_state.secret() {
return Err(Error::with_message(ErrorKind::Credential, || {
format!(
"State secret mismatch: expected {}, received: {}",
auth_obj.csrf_state.secret(),
state.secret()
)
}));
}
let message = "Authentication complete. You can close this window now.";
let response = format!(
"HTTP/1.1 200 OK\r\ncontent-length: {}\r\n\r\n{}",
message.len(),
message
);
stream.write_all(response.as_bytes()).unwrap();
return Ok(code);
}
unreachable!()
}