init commit
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -1,3 +1,5 @@
|
|||||||
|
.idea/
|
||||||
|
GIT_IGNORE.txt
|
||||||
# ---> macOS
|
# ---> macOS
|
||||||
# General
|
# General
|
||||||
.DS_Store
|
.DS_Store
|
||||||
|
|||||||
17
Cargo.toml
Normal file
17
Cargo.toml
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
[package]
|
||||||
|
name = "oidc_client_flow_login"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
rust_util = "0.6.41"
|
||||||
|
clap = "3.0.5"
|
||||||
|
base64 = "0.13.0"
|
||||||
|
urlencoding = "2.1.0"
|
||||||
|
reqwest = { version= "0.11.8", features = ["json", "socks"] }
|
||||||
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
|
serde_json = "1.0"
|
||||||
|
tokio = { version = "1.15.0", features = ["full"] }
|
||||||
|
|
||||||
@@ -1,2 +1,4 @@
|
|||||||
# oidc_client_flow_login
|
# oidc_client_flow_login
|
||||||
|
|
||||||
|
Google device code:
|
||||||
|
https://developers.google.com/identity/sign-in/devices
|
||||||
|
|||||||
112
src/main.rs
Normal file
112
src/main.rs
Normal file
@@ -0,0 +1,112 @@
|
|||||||
|
use std::collections::HashMap;
|
||||||
|
use std::env;
|
||||||
|
use std::process::exit;
|
||||||
|
use std::time::Duration;
|
||||||
|
use clap::{App, Arg};
|
||||||
|
use reqwest::{ClientBuilder, Proxy};
|
||||||
|
use rust_util::{debugging, information, opt_result, opt_value_result, XResult};
|
||||||
|
use rust_util::util_msg::MessageType;
|
||||||
|
use crate::oidc::{OpenIdClientConfiguration, OpenIdConfiguration};
|
||||||
|
|
||||||
|
mod oidc;
|
||||||
|
|
||||||
|
|
||||||
|
const NAME: &str = env!("CARGO_PKG_NAME");
|
||||||
|
const VERSION: &str = env!("CARGO_PKG_VERSION");
|
||||||
|
const AUTHORS: &str = env!("CARGO_PKG_AUTHORS");
|
||||||
|
const DESCRIPTION: &str = env!("CARGO_PKG_DESCRIPTION");
|
||||||
|
|
||||||
|
#[tokio::main]
|
||||||
|
async fn main() -> XResult<()> {
|
||||||
|
let matches = App::new(NAME)
|
||||||
|
.version(VERSION)
|
||||||
|
.about(DESCRIPTION)
|
||||||
|
.author(AUTHORS)
|
||||||
|
.arg(Arg::new("version").short('V').long("version").help("Print version"))
|
||||||
|
.arg(Arg::new("verbose").short('v').long("verbose").help("Verbose"))
|
||||||
|
.arg(Arg::new("issuer").short('i').long("issuer").takes_value(true).help("Issuer"))
|
||||||
|
.arg(Arg::new("proxy").short('p').long("proxy").takes_value(true).help("Proxy"))
|
||||||
|
.arg(Arg::new("skip-certificate-check").short('k').long("skip-certificate-check").help("Skip certificate check"))
|
||||||
|
.get_matches();
|
||||||
|
|
||||||
|
if matches.is_present("verbose") {
|
||||||
|
env::set_var("LOGGER_LEVEL", "*");
|
||||||
|
}
|
||||||
|
if matches.is_present("version") {
|
||||||
|
information!("{} v{}", NAME, VERSION);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
let issuer = opt_value_result!(matches.value_of("issuer"), "Issuer is required");
|
||||||
|
let openid_configuration_url = format!("{}/.well-known/openid-configuration", issuer);
|
||||||
|
debugging!("Open id configuration url: {}", openid_configuration_url);
|
||||||
|
|
||||||
|
let mut client_builder = ClientBuilder::new()
|
||||||
|
.timeout(Duration::from_secs(10))
|
||||||
|
.connect_timeout(Duration::from_secs(3));
|
||||||
|
if let Some(proxy) = matches.value_of("proxy") {
|
||||||
|
let proxy = opt_result!( Proxy::all(proxy), "Parse proxy: {} failed: {}", proxy);
|
||||||
|
client_builder = client_builder.proxy(proxy);
|
||||||
|
}
|
||||||
|
if (matches.is_present("skip-certificate-check")) {
|
||||||
|
client_builder = client_builder.danger_accept_invalid_certs(true);
|
||||||
|
}
|
||||||
|
let client = opt_result!( client_builder.build(), "Build reqwest client failed: {}");
|
||||||
|
|
||||||
|
debugging!("Sending request...");
|
||||||
|
let get_openid_configuration_result = opt_result!(
|
||||||
|
client.get(&openid_configuration_url).send().await, "Get url: {}, failed: {}", openid_configuration_url);
|
||||||
|
let openid_configuration = opt_result!(
|
||||||
|
get_openid_configuration_result.json::<OpenIdConfiguration>().await, "Parse open id configuration failed: {}");
|
||||||
|
|
||||||
|
rust_util::util_msg::when(MessageType::DEBUG, || {
|
||||||
|
debugging!("Return open id configuration: {}", serde_json::to_string_pretty(&openid_configuration).unwrap());
|
||||||
|
});
|
||||||
|
|
||||||
|
let device_authorization_endpoint = opt_value_result!(
|
||||||
|
openid_configuration.device_authorization_endpoint, "Open id configuration has not configured device authorization endpoint");
|
||||||
|
let token_endpoint = openid_configuration.token_endpoint;
|
||||||
|
let userinfo_endpoint = openid_configuration.userinfo_endpoint;
|
||||||
|
|
||||||
|
information!("device_authorization_endpoint: {}", &device_authorization_endpoint);
|
||||||
|
information!("token_endpoint: {}", &token_endpoint);
|
||||||
|
information!("userinfo_endpoint: {}", &userinfo_endpoint);
|
||||||
|
|
||||||
|
let openid_client_configuration = OpenIdClientConfiguration {
|
||||||
|
issuer: "".into(),
|
||||||
|
client_id: "".into(),
|
||||||
|
client_secret: "".into(),
|
||||||
|
scope: "".into(),
|
||||||
|
};
|
||||||
|
|
||||||
|
// xh POST https://oauth2.googleapis.com/device/code
|
||||||
|
// client_id==364023986785-o5mqsqd1ej2d1vmvcqai108b7m7v7vc9.apps.googleusercontent.com scope=openid
|
||||||
|
//{
|
||||||
|
// "device_code": "***",
|
||||||
|
// "user_code": "STLB-RNKS",
|
||||||
|
// "expires_in": 1800,
|
||||||
|
// "interval": 5,
|
||||||
|
// "verification_url": "https://www.google.com/device"
|
||||||
|
// }
|
||||||
|
let mut params = HashMap::new();
|
||||||
|
params.insert("client_id", &openid_client_configuration.issuer);
|
||||||
|
params.insert("scope", &openid_client_configuration.scope);
|
||||||
|
let token_endpoint_builder = opt_result!(client.post(&device_authorization_endpoint)
|
||||||
|
.form(params).send().await, "Get token: {}, failed: {}", device_authorization_endpoint);
|
||||||
|
// token_endpoint_builder.
|
||||||
|
|
||||||
|
// xh POST https://oauth2.googleapis.com/token
|
||||||
|
// client_id==364023986785-o5mqsqd1ej2d1vmvcqai108b7m7v7vc9.apps.googleusercontent.com
|
||||||
|
// client_secret==***
|
||||||
|
// device_code==***
|
||||||
|
// grant_type==urn:ietf:params:oauth:grant-type:device_code
|
||||||
|
// {
|
||||||
|
// "access_token": "***",
|
||||||
|
// "expires_in": 3599,
|
||||||
|
// "refresh_token": "***",
|
||||||
|
// "scope": "openid",
|
||||||
|
// "token_type": "Bearer",
|
||||||
|
// "id_token": "***"
|
||||||
|
// }
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
44
src/oidc.rs
Normal file
44
src/oidc.rs
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
use serde::{Serialize, Deserialize};
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
|
pub struct OpenIdClientConfiguration {
|
||||||
|
pub issuer: String,
|
||||||
|
pub client_id: String,
|
||||||
|
pub client_secret: String,
|
||||||
|
pub scope: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
|
pub struct OpenIdConfiguration {
|
||||||
|
pub issuer: String,
|
||||||
|
pub authorization_endpoint: String,
|
||||||
|
pub device_authorization_endpoint: Option<String>,
|
||||||
|
pub token_endpoint: String,
|
||||||
|
pub userinfo_endpoint: String,
|
||||||
|
pub revocation_endpoint: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
|
pub struct ErrorResponse {
|
||||||
|
pub error: String,
|
||||||
|
pub error_description: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
|
pub struct DeviceAuthorizationResponse {
|
||||||
|
pub device_code: String,
|
||||||
|
pub user_code: String,
|
||||||
|
pub expires_in: i64,
|
||||||
|
pub interval: i64,
|
||||||
|
pub verification_url: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
|
pub struct TokenResponse {
|
||||||
|
pub access_token: String,
|
||||||
|
pub refresh_token: String,
|
||||||
|
pub scope: Option<String>,
|
||||||
|
pub token_type: String,
|
||||||
|
pub id_token: Option<String>,
|
||||||
|
pub expires_in: i64,
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user