Skip to content

Commit

Permalink
oauth2 cloud login (#205)
Browse files Browse the repository at this point in the history
* Initial rust part of oauth2 cloud login

* wip

* minor updates

* Added default parameter support

* Fix lint

* Bump beta version of package

* Removed unneeded constants

* Verified other flow tests
  • Loading branch information
simlay authored Dec 29, 2022
1 parent 848ae52 commit 0572859
Show file tree
Hide file tree
Showing 11 changed files with 1,808 additions and 37 deletions.
1,148 changes: 1,115 additions & 33 deletions Cargo.lock

Large diffs are not rendered by default.

21 changes: 20 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,23 @@ log = "^0.4.17"
cpython = { version = "0.7", features = ["extension-module"] }
flate2 = "1.0.24"
fluvio = { version = "0.15" }
fluvio-future = { version = "0.4.2", features = ["task", "io"] }
fluvio-future = { version = "0.4.2", features = ["task", "io", "native2_tls", "subscriber"] }

thiserror = "1.0.21"
fluvio-types = "0.4.0"
serde = "1.0.117"
tracing = "0.1.37"

url = "2.1.1"
dirs = "4.0.0"
http-types = "2.6.0"
tokio = { version = "1.3.0", default-features = false, features = ["macros"] }
async-h1 = "2.3.3"
async-std = "1.6.5"
serde_urlencoded = "0.7.1"
md-5 = "0.10.0"
hex = "0.4.2"
webbrowser = "0.7.1"
toml = "0.5.7"
serde_json = "1.0.59"
rpassword = "5.0.0"
3 changes: 3 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ integration-tests: build-dev
macos-ci-tests: build-dev
cd macos-ci-tests && $(PYTHON) -m unittest

manual-tests: build-dev
cd manual-tests/ && $(PYTHON) -m unittest

ci-build: # This is for testing builds
CIBW_BUILD="cp311-manylinux_x86_64 cp311-manylinux_aarch64 cp311-macosx_x86_64 cp311-macosx_universal2 cp311-macosx_arm64" CIBW_SKIP="cp27-*" CIBW_BEFORE_ALL_LINUX="{package}/tools/cibw_before_all_linux.sh" $(PYTHON) -m cibuildwheel --platform linux --output-dir wheelhouse

Expand Down
13 changes: 13 additions & 0 deletions fluvio/cloud.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
from ._fluvio_python import Cloud

DEFAULT_REMOTE = "https://infinyon.cloud"


def login(
useOauth2=True,
remote=DEFAULT_REMOTE,
profile=None,
email=None,
password=None,
):
Cloud.login(useOauth2, remote, profile, email, password)
11 changes: 11 additions & 0 deletions manual-tests/test_cloud_login.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import unittest
from fluvio.cloud import login


class TestFluvioCloudLogin(unittest.TestCase):
def test_login(self):
login()
# Comment/uncomment these as needed.
#login(profile='test-profile')
#login(useOauth2=False, email='youremail@gmail.com', password='PUT_YOURPASSWORD_HERE')
#login(useOauth2=False)
5 changes: 2 additions & 3 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@

setup(
name='fluvio',
version="0.14.1-beta.0",
version="0.14.1-beta.1",
long_description=open('README.md').read(),
long_description_content_type='text/markdown',
author = "Fluvio Contributors",
description='Python client library for Fluvio',
python_requires='>=3.7',
python_requires='>=3.8',
url='https://www.fluvio.io/',
keywords=['fluvio', 'streaming', 'stream'],
license='APACHE',
Expand All @@ -30,7 +30,6 @@
# that you indicate you support Python 3. These classifiers are *not*
# checked by 'pip install'. See instead 'python_requires' below.
'Programming Language :: Python :: 3',
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8',
'Programming Language :: Python :: 3.9',
'Programming Language :: Python :: 3.10',
Expand Down
69 changes: 69 additions & 0 deletions src/cloud/error.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
use fluvio::FluvioError;
use http_types::url::ParseError;
use http_types::StatusCode;
use std::io::Error as IoError;
use std::path::PathBuf;
use thiserror::Error;
use toml::de::Error as TomlError;

#[derive(Error, Debug)]
pub enum CloudLoginError {
#[error("Unable to access the default Fluvio directory")]
FluvioDirError,
/// Failed to parse request URL
#[error("Failed to parse URL: {url_string}")]
UrlError {
source: ParseError,
url_string: String,
},
#[error("Failed to make HTTP request to Infinyon cloud")]
HttpError(#[source] HttpError),
#[error("Failed to get token from Auth0")]
FailedToGetAuth0Token,
#[error("Failed to authenticate with Auth0: {0}")]
Auth0LoginError(String),
#[error("Account not found with email provided by third party service, please create account through WEB UI.")]
Auth0AccountNotFound,
#[error("Timeout while waiting for user authentication through third party service.")]
Auth0TimeoutError,
#[error("Unable to url encode the string")]
UrlEncode(#[from] serde_urlencoded::ser::Error),
#[error("Failed to save cloud credentials")]
UnableToSaveCredentials(#[source] IoError),
/// Failed to do some IO.
#[error(transparent)]
IoError(#[from] IoError),
#[error("Failed to create logins dir {path}")]
UnableToCreateLoginsDir { source: IoError, path: PathBuf },
#[error("Cluster for \"{0}\" does not exist")]
ClusterDoesNotExist(String),
#[error("Profile not available yet, please try again later.")]
ProfileNotAvailable,
#[error("Failed to parse login token from file")]
UnableToParseCredentials(#[from] TomlError),
#[error("Failed to load cloud credentials")]
UnableToLoadCredentials(#[source] IoError),
#[error("Failed to download cloud profile: Status code {0}: {1}")]
ProfileDownloadError(StatusCode, &'static str),
/// Failed to open Infinyon Cloud login file
#[error("Not logged in")]
NotLoggedIn,
#[error("Fluvio client error")]
FluvioError(#[from] FluvioError),
#[error("Failed to authenticate with username: {0}")]
AuthenticationError(String),
#[error("Account not active. Please validate email address.")]
AccountNotActive,
}

#[derive(Error, Debug)]
#[error("An HTTP error occurred: {inner}")]
pub struct HttpError {
inner: http_types::Error,
}

impl From<http_types::Error> for CloudLoginError {
fn from(inner: http_types::Error) -> Self {
Self::HttpError(HttpError { inner })
}
}
42 changes: 42 additions & 0 deletions src/cloud/http.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
use async_h1::client;
use http_types::{headers::USER_AGENT, Error, Request, Response, StatusCode};
use tracing::debug;

pub const FLUVIO_CLI_USER_AGENT: &str = "Fluvio Python Client";

pub async fn execute(req: Request) -> Result<Response, Error> {
debug!(?req, "executing request");
let mut req = req;
let host = req
.url()
.host_str()
.ok_or_else(|| Error::from_str(StatusCode::BadRequest, "missing hostname"))?
.to_string();

let is_https = req.url().scheme() == "https";

let addr = req
.url()
.socket_addrs(|| if is_https { Some(443) } else { Some(80) })?
.into_iter()
.next()
.ok_or_else(|| Error::from_str(StatusCode::BadRequest, "missing valid address"))?;

let tcp_stream = fluvio_future::net::TcpStream::connect(addr).await?;

req.append_header(
USER_AGENT,
format!("{}/{}", FLUVIO_CLI_USER_AGENT, env!("CARGO_PKG_VERSION")),
);

let result = if is_https {
let tls_connector = fluvio_future::native_tls::TlsConnector::default();
let tls_stream = tls_connector.connect(host, tcp_stream).await?;
client::connect(tls_stream, req).await
} else {
client::connect(tcp_stream, req).await
};

debug!(?result, "http result");
result
}
Loading

0 comments on commit 0572859

Please sign in to comment.