add http basic auth

This commit is contained in:
Bevan Hunt 2021-03-25 13:19:27 -07:00
parent 0ab4c72281
commit 31bbed2019
5 changed files with 55 additions and 17 deletions

View File

@ -4,6 +4,11 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [8.1.x] - 2021-04-25
### Added
- Adds http basic auth
## [8.0.x] - 2021-03-23
### Added

3
Cargo.lock generated
View File

@ -461,10 +461,11 @@ dependencies = [
[[package]]
name = "broker"
version = "8.0.0"
version = "8.1.0"
dependencies = [
"anyhow",
"async-std",
"base64 0.13.0",
"driftwood",
"futures",
"go-flag",

View File

@ -1,6 +1,6 @@
[package]
name = "broker"
version = "8.0.0"
version = "8.1.0"
authors = ["Bevan Hunt <bevan@bevanhunt.com>"]
edition = "2018"
license = "MIT"
@ -31,3 +31,4 @@ http-types = "2"
tide-rustls = "0.3"
futures = "0.3"
tide-acme = "0.1.0"
base64 = "0.13"

View File

@ -21,7 +21,8 @@ Broker follows an insert-only/publish/subscribe paradigm rather than a REST CRUD
* Add users with admin token permission
* Multi-tenant
* Supports SSL - full end-to-end encryption
* Provides user authentication with JWTs with stored Argon2 passwords
* Provides user authentication with JWTs or HTTP Basic
* Secure passwords with Argon2 encoding
* Uses Global NTP servers and doesn't rely on your local server time
* Insert event via JSON POST request
* Sync latest events on SSE client connection
@ -90,7 +91,7 @@ will return
```html
GET /sse
```
- authenticated endpoint (Authorization: Bearer {jwt})
- authenticated endpoint (Authorization: Bearer {jwt}) or (Authorization: Basic {username:password})
- connect your sse-client to this endpoint using [broker-client](https://www.npmjs.com/package/broker-client)
- `note`: broker-client uses fetch as eventsource doesn't support headers
@ -99,7 +100,7 @@ GET /sse
```html
POST /insert
```
- authenticated endpoint (Authorization: Bearer {jwt})
- authenticated endpoint (Authorization: Bearer {jwt}) or (Authorization: Basic {username:password})
- POST JSON to insert an event
```json
{"event":{...}, "data":{...}, "tenant_name":{...}}

View File

@ -219,7 +219,7 @@ fn env_var_config() -> EnvVarConfig {
EnvVarConfig{port, origin, jwt_expiry, jwt_secret, secure, domain, certs, db, admin_token}
}
fn jwt_verify(token: String) -> Result<Option<TokenData<Claims>>> {
async fn jwt_verify(token: String) -> Result<Option<TokenData<Claims>>> {
let configure = env_var_config();
@ -228,16 +228,45 @@ fn jwt_verify(token: String) -> Result<Option<TokenData<Claims>>> {
if auth_type == "Bearer" {
let token = parts.next().unwrap();
let _ = match decode::<Claims>(&token, &DecodingKey::from_secret(configure.jwt_secret.as_ref()), &Validation::default()) {
Ok(c) => {
return Ok(Some(c));
},
Err(_) => {
return Ok(None);
}
Ok(c) => { return Ok(Some(c)); },
Err(_) => { return Ok(None); }
};
} else if auth_type == "Basic" {
let basic_encoded = parts.next().unwrap();
let _ = match base64::decode(basic_encoded) {
Ok(c) => {
let _ = match std::str::from_utf8(&c) {
Ok(basic) => {
let mut basic_parts = basic.split(":");
let user_name = basic_parts.next().unwrap();
let password = basic_parts.next().unwrap();
let user_value = get_user_by_username(user_name.to_string())?;
match user_value {
Some(user) => {
if argon2::verify_encoded(&user.password, password.as_ref())? {
let app = env_var_config();
let iat = nippy::get_unix_ntp_time().await?;
let exp = iat + app.jwt_expiry;
let iss = "Dispatcher".to_string();
let my_claims = Claims{sub: user.clone().username, exp, iat, iss};
let my_token = TokenData{
header: Header::default(),
claims: my_claims,
};
return Ok(Some(my_token));
}
},
None => { return Ok(None); }
}
},
Err(_) => { return Ok(None); }
};
},
Err(_) => { return Ok(None); }
};
} else {
Ok(None)
}
Ok(None)
}
// insert an event
@ -301,7 +330,7 @@ async fn insert_event(mut req: Request<()>) -> tide::Result {
match token_value {
Some(token_header) => {
let token = token_header.last().to_string();
let jwt_value = jwt_verify(token)?;
let jwt_value = jwt_verify(token).await?;
match jwt_value {
Some(jwt) => {
let r = req.body_string().await?;
@ -340,13 +369,14 @@ async fn main() -> tide::Result<()> {
match token_value {
Some(token_header) => {
let token = token_header.last().to_string();
let jwt_value = jwt_verify(token)?;
let jwt_value = jwt_verify(token).await?;
match jwt_value {
Some(jwt) => {
let user_value = get_user_by_username(jwt.claims.sub)?;
match user_value {
Some(user) => {
let mut cache: HashMap<String, Event> = HashMap::new();
let mut interval = stream::interval(Duration::from_millis(100));
@ -369,7 +399,7 @@ async fn main() -> tide::Result<()> {
cache.insert(evt.event.clone(), evt.clone());
}
},
None => { return Ok(()); }
None => { println!("helo"); return Ok(()); }
}
}
}