Compare commits

...

6 Commits

Author SHA1 Message Date
Bevan Hunt 268b3acf9f update readme 2021-04-30 17:58:29 -07:00
Bevan Hunt 791c1b6d6b add scopes to verify endpoint 2021-04-30 17:57:04 -07:00
Bevan Hunt c868cab517 update to 15.0.0 2021-04-16 13:41:17 -07:00
Bevan Hunt 45ff26c460 update readme 2021-04-15 18:10:58 -07:00
Bevan Hunt 323273ce24 update changelog 2021-04-14 18:03:13 -07:00
Bevan Hunt 80840114c3 update readme 2021-04-14 18:02:31 -07:00
5 changed files with 40 additions and 15 deletions

View File

@ -4,6 +4,29 @@ 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/), 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). and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [15.1.0] - 2021-04-30
### Added
- scopes to verify endpoint
## [15.0.0] - 2021-04-16
### Added
- username to verify endpoint and JWT
### Updated
- Updated README
## [14.1.2] - 2021-04-15
### Updated
- Updated README
## [14.1.1] - 2021-04-14
### Updated
- Updated README
## [14.1.0] - 2021-04-13 ## [14.1.0] - 2021-04-13
### Added ### Added

2
Cargo.lock generated
View File

@ -543,7 +543,7 @@ dependencies = [
[[package]] [[package]]
name = "broker" name = "broker"
version = "14.1.0" version = "15.1.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"async-std", "async-std",

View File

@ -1,6 +1,6 @@
[package] [package]
name = "broker" name = "broker"
version = "14.1.0" version = "15.1.0"
authors = ["Bevan Hunt <bevan@bevanhunt.com>"] authors = ["Bevan Hunt <bevan@bevanhunt.com>"]
edition = "2018" edition = "2018"
license = "MIT" license = "MIT"

View File

@ -14,7 +14,7 @@ Broker follows an insert-only/publish/subscribe paradigm rather than a REST CRUD
Broker also provides full identity services using JWT, HTTP Basic, Two Factor, and TOTP. Broker also provides full identity services using JWT, HTTP Basic, Two Factor, and TOTP.
Broker is a competitor to [Firebase](https://firebase.google.com/), [Parse Server](https://github.com/parse-community/parse-server), [Auth0](https://auth0.com), [AWS Cognito](https://aws.amazon.com/cognito/), [AWS SimpleDB](https://aws.amazon.com/simpledb/), and [AWS SNS](https://aws.amazon.com/sns/). Broker is a competitor to [Firebase](https://firebase.google.com/), [Parse Server](https://github.com/parse-community/parse-server), [Auth0](https://auth0.com), [AWS Cognito](https://aws.amazon.com/cognito/), [AWS IAM](https://aws.amazon.com/iam/), [AWS SimpleDB](https://aws.amazon.com/simpledb/), and [AWS SNS](https://aws.amazon.com/sns/).
### Features ### Features
@ -29,7 +29,7 @@ Broker is a competitor to [Firebase](https://firebase.google.com/), [Parse Serve
* Provides user authentication with JWTs or HTTP Basic * Provides user authentication with JWTs or HTTP Basic
* Issues JWTs for authentication (username) and authorization (scopes) for external services * Issues JWTs for authentication (username) and authorization (scopes) for external services
* Uses [biscuit](https://crates.io/crates/biscuit-auth) for user authorization scoping * Uses [biscuit](https://crates.io/crates/biscuit-auth) for user authorization scoping
* Verify endpoint for external services like [portal](https://crates.io/crates/portal) * Verify endpoint for external services like [portal](https://crates.io/crates/portal) and [files](https://crates.io/crates/files)
* Secure password storage with Argon2 encoding * Secure password storage with Argon2 encoding
* Uses Global NTP servers and doesn't rely on your local server time for JWT expiry timing and Two Factor timing * Uses Global NTP servers and doesn't rely on your local server time for JWT expiry timing and Two Factor timing
* Sync latest events on SSE client connection * Sync latest events on SSE client connection
@ -147,12 +147,14 @@ GET /verify
will return: `200` or `500` or `401` will return: `200` or `500` or `401`
200 - will return a biscuit public key, biscuit token, and JWT expiry for your microservice (use from_bytes to hydrate the key and token) 200 - will return a biscuit public key, biscuit token, username, and JWT expiry for your microservice (use from_bytes to hydrate the key and token)
```json ```json
{ {
"key": [136,133,229,196,134,20,240,80,159,158,154,20,57,35,198,7,156,160,193,224,174,209,51,150,27,86,75,122,172,24,114,66], "key": [136,133,229,196,134,20,240,80,159,158,154,20,57,35,198,7,156,160,193,224,174,209,51,150,27,86,75,122,172,24,114,66],
"token": [122,133,229,196,134,20,240,80,159,158,154,20,57,35,198,7,156,160,193,224,174,209,51,150,27,86,75,122,172,24,114,121], "token": [122,133,229,196,134,20,240,80,159,158,154,20,57,35,198,7,156,160,193,224,174,209,51,150,27,86,75,122,172,24,114,121],
"expiry: 1618352841 "expiry": 1618352841,
"username": "bob",
"scopes": ["news:get", "news:post"]
} }
``` ```
@ -195,7 +197,7 @@ POST /list_users
- public endpoint - public endpoint
```json ```json
{ {
"admin_token": "letmein", "admin_token": "letmein"
} }
``` ```
@ -323,7 +325,7 @@ POST /create_totp
```json ```json
{ {
"admin_token": "letmein", "admin_token": "letmein",
"username": "bob", "username": "bob"
} }
``` ```
will return: `200` or `500` or `400` or `401` will return: `200` or `500` or `400` or `401`

View File

@ -311,14 +311,14 @@ fn puts_event(event: Event) -> Result<()> {
Ok(()) Ok(())
} }
fn jwt_aud(scopes: Vec<String>, exp: i64) -> Result<Option<String>> { fn jwt_aud(scopes: Vec<String>, exp: i64, username: String) -> Result<Option<String>> {
let biscuit_root = KeyPair::new(); let biscuit_root = KeyPair::new();
let biscuit_public_key = biscuit_root.public(); let biscuit_public_key = biscuit_root.public();
let public_key_bytes = biscuit_public_key.to_bytes(); let public_key_bytes = biscuit_public_key.to_bytes();
let mut builder = Biscuit::builder(&biscuit_root); let mut builder = Biscuit::builder(&biscuit_root);
for scope in scopes { for scope in scopes.clone() {
let mut parts = scope.split(":"); let mut parts = scope.split(":");
let first = parts.next().unwrap_or_else(|| "INTERNAL_ERROR"); let first = parts.next().unwrap_or_else(|| "INTERNAL_ERROR");
let second = parts.next().unwrap_or_else(|| "INTERNAL_ERROR"); let second = parts.next().unwrap_or_else(|| "INTERNAL_ERROR");
@ -331,7 +331,7 @@ fn jwt_aud(scopes: Vec<String>, exp: i64) -> Result<Option<String>> {
} }
let biscuit = builder.build()?; let biscuit = builder.build()?;
Ok(Some(json!({"key": public_key_bytes, "token": biscuit.to_vec()?, "expiry": exp}).to_string())) Ok(Some(json!({"key": public_key_bytes, "token": biscuit.to_vec()?, "expiry": exp, "username": username, "scopes": scopes}).to_string()))
} }
fn user_create(user_form: UserForm) -> Result<Option<String>> { fn user_create(user_form: UserForm) -> Result<Option<String>> {
@ -457,7 +457,7 @@ async fn create_jwt(login: LoginForm) -> Result<Option<String>> {
let aud: String; let aud: String;
match user.scopes.clone() { match user.scopes.clone() {
Some(scopes) => { Some(scopes) => {
match jwt_aud(scopes, exp)? { match jwt_aud(scopes, exp, user.clone().username)? {
Some(a) => { Some(a) => {
aud = a; aud = a;
}, },
@ -483,7 +483,7 @@ async fn create_jwt(login: LoginForm) -> Result<Option<String>> {
let aud: String; let aud: String;
match user.scopes.clone() { match user.scopes.clone() {
Some(scopes) => { Some(scopes) => {
match jwt_aud(scopes, exp)? { match jwt_aud(scopes, exp, user.clone().username)? {
Some(a) => { Some(a) => {
aud = a; aud = a;
}, },
@ -505,7 +505,7 @@ async fn create_jwt(login: LoginForm) -> Result<Option<String>> {
let aud: String; let aud: String;
match user.scopes.clone() { match user.scopes.clone() {
Some(scopes) => { Some(scopes) => {
match jwt_aud(scopes, exp)? { match jwt_aud(scopes, exp, user.clone().username)? {
Some(a) => { Some(a) => {
aud = a; aud = a;
}, },
@ -599,7 +599,7 @@ async fn jwt_verify(token: String) -> Result<Option<TokenData<Claims>>> {
let aud: String; let aud: String;
match user.scopes.clone() { match user.scopes.clone() {
Some(scopes) => { Some(scopes) => {
match jwt_aud(scopes, exp)? { match jwt_aud(scopes, exp, user.clone().username)? {
Some(a) => { Some(a) => {
aud = a; aud = a;
}, },