azure_identity/
development.rs
1use crate::authorization_code_flow::AuthorizationCodeFlow;
5use azure_core::{
6 error::{Error, ErrorKind},
7 Url,
8};
9use oauth2::{AuthorizationCode, CsrfToken};
10use std::{
11 io::{BufRead, BufReader, Write},
12 net::TcpListener,
13};
14use tracing::debug;
15
16pub fn naive_redirect_server(
23 auth_obj: &AuthorizationCodeFlow,
24 port: u16,
25) -> azure_core::Result<AuthorizationCode> {
26 let listener = TcpListener::bind(format!("127.0.0.1:{port}")).unwrap();
27
28 if let Some(mut stream) = listener.incoming().flatten().next() {
30 let mut reader = BufReader::new(&stream);
31
32 let mut request_line = String::new();
33 reader.read_line(&mut request_line).unwrap();
34
35 let Some(redirect_url) = request_line.split_whitespace().nth(1) else {
36 return Err(Error::with_message(ErrorKind::Credential, || {
37 format!("unexpected redirect url: {request_line}")
38 }));
39 };
40 let url = Url::parse(&("http://localhost".to_string() + redirect_url)).unwrap();
41
42 debug!("url == {}", url);
43
44 let code = match url.query_pairs().find(|(key, _)| key == "code") {
45 Some((_, value)) => AuthorizationCode::new(value.into_owned()),
46 None => {
47 return Err(Error::message(
48 ErrorKind::Credential,
49 "query pair not found: code",
50 ))
51 }
52 };
53
54 let state = match url.query_pairs().find(|(key, _)| key == "state") {
55 Some((_, value)) => CsrfToken::new(value.into_owned()),
56 None => {
57 return Err(Error::message(
58 ErrorKind::Credential,
59 "query pair not found: state",
60 ))
61 }
62 };
63
64 if state.secret() != auth_obj.csrf_state.secret() {
65 return Err(Error::with_message(ErrorKind::Credential, || {
66 format!(
67 "State secret mismatch: expected {}, received: {}",
68 auth_obj.csrf_state.secret(),
69 state.secret()
70 )
71 }));
72 }
73
74 let message = "Authentication complete. You can close this window now.";
75 let response = format!(
76 "HTTP/1.1 200 OK\r\ncontent-length: {}\r\n\r\n{}",
77 message.len(),
78 message
79 );
80 stream.write_all(response.as_bytes()).unwrap();
81
82 return Ok(code);
83 }
84
85 unreachable!()
86}