Skip to content

Commit

Permalink
remove discord from documentations (#47)
Browse files Browse the repository at this point in the history
  • Loading branch information
thebino committed Jul 26, 2024
1 parent b1354be commit 7e396f2
Show file tree
Hide file tree
Showing 3 changed files with 112 additions and 11 deletions.
3 changes: 2 additions & 1 deletion crates/database/src/sqlite.rs
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,8 @@ impl Database for SqliteDatabase {
}

async fn get_media_items(&self, _user_id: &str) -> Result<Vec<MediaItem>> {
unimplemented!()
error!("get_media_items not implemented!");
Ok(vec![])
}
async fn create_media_item(
&self,
Expand Down
51 changes: 50 additions & 1 deletion crates/oauth_authorization_server/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,53 @@

This crate offers an **OAuth Authorization Server** for [Photos.network](https://photos.network).

Especially for data privacy or offline support, this can interact as its own authorization server to handle user accounts locally without using any third-party authorization like Google, Okta or Microsoft.
Especially for data privacy and offline support, this can interact as its own authorization server to handle user accounts locally without using any third-party authorization like Google, Okta or Microsoft.

To identify users and granting them access to the applications content, the Open Authorization (OAuth) standard is used so users can login without sharing credentials theirselfs.
Since public clients (e.g. native mobile applications and single-page applications) cannot securely store client secrets.
Clients need to implement [PKCE](https://datatracker.ietf.org/doc/html/rfc7636) and create a pair of secrets (Code Verifier & Code Challenge) and send it to this **OAuth Authorization Server** over https.
This way a malicious attacker can only intercept the Authorization Code but can't exchange it for a token without knowing the Code Verifier.


## Authorization code flow with PKCE
```mermaid
sequenceDiagram;
participant U as Users
participant A as App
participant AM as Authorization Server
participant R as Resource Server
U->>A: User clicks login
A->>AM: GET http://127.0.0.1/.well-known/openid-configuration
AM->>A: JSON meta-data document
Note right of A: { "authorization_endpoint":"http://localhost:7777/oidc/authorize", <br> "token_endpoint":"http://localhost:7777/oidc/token" ...
A->>A: Generate Code Verifier & Challenge
A->>AM: GET http://localhost:7777/oidc/authorize?[...]
Note right of A: GET /oidc/authorize parameters: <br> response_type=id_token%20token <br> client_id=mobile-app (identifier) <br> redirect_uri=photosapp://authenticate <br> state=xxxx (CRFS protection) <br> nonce=xyz (server-side replay protection) <br> scope=openid email profile library:read <br> code_challenge=elU6u5zyqQT2f92GRQUq6PautAeNDf4DQPayy <br> code_challenge_method=S256
AM->>U: show login prompt
U->>AM: perform login and grant consent
AM->>A: 302 Redirect to http://127.0.0.1/callback?[...] (redirect_uri)
Note right of A: GET /callback <br> state=xxx <br> code=xxx
A->>AM: GET http://localhost:7777/oidc/token
Note right of A: GET /oidc/token parameters: <br> client_id=xxx (identifier) <br> redirect_uri=http://127.0.0.1/callback <br> code_verifier=xxxx (generated verifier) <br> code=xyz (authorization_code) <br> grant_type=authorization_code
AM->>AM: Validate code verifier and challenge
AM->>A: ID Token and Access token
Note right of A: { <br> "token_type": "Bearer", <br> "expires_in": 3600, <br> "access_token": "eyJraWQiOiI3bFV0aGJyR2hWVmx...",<br> "id_token": "eyJraWQiOiI3bFV0aGJyR2hWVmx...",<br> "scope": "profile openid email" <br> }
%% R->>A: return user attributes
%% U->>O: GET http://127.0.0.1/callback?[...]
%% O->>A: POST http://127.0.0.1:7777/oidc/token
%% Note right of O: POST /oidc/token <br> client_id=xxx <br> grant_type=authorization_code <br> code=xxx <br> state=xxx
%% A->>O: JSON { "base64(id_token)", access_token" }
%% O->>O: verify id_token signature is valid and signed
%% O->>U: GET 302 Redirect to http://127.0.0.1
Note over A: User is authenticate to http://127.0.0.1
A->>R: Request user data with Access Token
R->>A: responds with requested data
```

69 changes: 60 additions & 9 deletions crates/oauth_authorization_server/src/handler/login.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,22 +20,73 @@ use axum::Form;

use serde::Deserialize;

static LOGIN_FORM_TEMPLATE: &str = r#"
<html>
<head>
<script src="https://cdn.tailwindcss.com?plugins=forms,typography,aspect-ratio,line-clamp"></script>
<script>
tailwind.config = {
theme: {
extend: {
colors: {
clifford: '#da373d',
accent: '#706CF6',
error: '#F2BAB9',
success: '#D2ECAE',
warn: '#F9F4BC',
neutral: '#CEEFF4',
}
}
}
}
</script>
<style type="text/tailwindcss">
@layer utilities {
.content-auto {
content-visibility: auto;
}
}
</style>
<style>
body {font-family: Arial, Helvetica, sans-serif;}
form {border: 3px solid #f1f1f1;}
</style>
</head>
<body>
<form method="post">
<label for="username" class="leading-7 text-sm text-gray-600"><b>Username</b></label>
<input type="text" id="username" name="username" class="w-full bg-white rounded border border-gray-300 focus:border-indigo-500 focus:ring-2 focus:ring-indigo-200 text-base outline-none text-gray-700 py-1 px-3 leading-8 transition-colors duration-200 ease-in-out" />
<label for="password" class="leading-7 text-sm text-gray-600"><b>Password</b></label>
<input type="password" id="password" name="password" class="w-full bg-white rounded border border-gray-300 focus:border-indigo-500 focus:ring-2 focus:ring-indigo-200 text-base outline-none text-gray-700 py-1 px-3 leading-8 transition-colors duration-200 ease-in-out" />
<input type="hidden" id="request_id" name="request_id" value="{{request_id}}" />
<input type="submit" id="submit" value="Submit" class="text-white bg-indigo-500 border-0 py-2 px-6 focus:outline-none hover:bg-indigo-600 rounded text-lg" />
</form>
</body>
</html>
"#;

pub(crate) async fn get_realm_login_form(
axum::extract::Path(_realm): axum::extract::Path<String>,
// Query(query): Query<LoginQuery>,
axum::extract::Path(realm): axum::extract::Path<String>,
axum::extract::Query(query): axum::extract::Query<LoginQuery>,
) -> Html<String> {
// create a VirtualDom with the app component
// rebuild the VirtualDom before rendering

// tracing::debug!(
// "Rendering form for request_id={} and realm={}",
// query.request_id,
// realm
// );
tracing::debug!(
"Rendering form for request_id={} and realm={}",
query.request_id,
realm
);

// render the VirtualDom to HTML
// Html(dioxus_ssr::render(&app))
Html("Login".to_string())
Html(LOGIN_FORM_TEMPLATE.to_string())
//Html("<h1>Login</h1><form method='post'><label for=\"username\"><b>Username</b></label` y><input type=\"text\" placeholder=\"Enter Username\" name=\"username\" required>i
//<label for=\"password\"><b>Password</b></label><input type=\"password\" placeholder=\"Enter Password\" name=\"password\" required><button type=\"submit\">Login</button></form>".to_string())
}

pub(crate) async fn post_realm_login(Form(login_form): Form<LoginFormData>) -> Html<String> {
Expand All @@ -52,7 +103,7 @@ pub(crate) async fn post_realm_login(Form(login_form): Form<LoginFormData>) -> H

#[derive(Debug, Deserialize)]
pub(crate) struct LoginQuery {
_request_id: String,
request_id: String,
}

#[derive(Debug, Deserialize)]
Expand Down

0 comments on commit 7e396f2

Please sign in to comment.