Skip to content

Commit

Permalink
feat: Change PAPI login to use text keycloak instance (TT-1430) (#30)
Browse files Browse the repository at this point in the history
  • Loading branch information
MariusLevang authored Feb 14, 2024
1 parent e3a01d9 commit 591b4d0
Show file tree
Hide file tree
Showing 8 changed files with 107 additions and 12 deletions.
8 changes: 7 additions & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,9 @@ jobs:
OIDC_BASE_URL: ${{ steps.import-secrets.outputs.TROKK_OIDC_BASE_URL }}
OIDC_CLIENT_ID: ${{ steps.import-secrets.outputs.TROKK_OIDC_CLIENT_ID }}
OIDC_CLIENT_SECRET: ${{ steps.import-secrets.outputs.TROKK_OIDC_CLIENT_SECRET }}
OIDC_TEKST_BASE_URL: ${{ steps.import-secrets.outputs.TROKK_OIDC_TEKST_BASE_URL }}
OIDC_TEKST_CLIENT_ID: ${{ steps.import-secrets.outputs.TROKK_OIDC_TEKST_CLIENT_ID }}
OIDC_TEKST_CLIENT_SECRET: ${{ steps.import-secrets.outputs.TROKK_OIDC_TEKST_CLIENT_SECRET }}

# TODO run backend tests when they exist

Expand Down Expand Up @@ -123,6 +126,9 @@ jobs:
OIDC_BASE_URL: ${{ steps.import-secrets.outputs.TROKK_OIDC_BASE_URL }}
OIDC_CLIENT_ID: ${{ steps.import-secrets.outputs.TROKK_OIDC_CLIENT_ID }}
OIDC_CLIENT_SECRET: ${{ steps.import-secrets.outputs.TROKK_OIDC_CLIENT_SECRET }}
OIDC_TEKST_BASE_URL: ${{ steps.import-secrets.outputs.TROKK_OIDC_TEKST_BASE_URL }}
OIDC_TEKST_CLIENT_ID: ${{ steps.import-secrets.outputs.TROKK_OIDC_TEKST_CLIENT_ID }}
OIDC_TEKST_CLIENT_SECRET: ${{ steps.import-secrets.outputs.TROKK_OIDC_TEKST_CLIENT_SECRET }}

- name: Setup JFrog CLI
uses: jfrog/setup-jfrog-cli@v3
Expand All @@ -142,4 +148,4 @@ jobs:
sed -e 's#\\#/#g' -e 's#//#/#g' |
jq -r .[] |
sed -n -e 's/^.*bundle\///p' |
xargs -I % jf rt u --url ${{ steps.import-secrets.outputs.ART_ARTIFACTORY_URL }} --user ${{ steps.import-secrets.outputs.ART_ARTIFACTORY_USER }} --password ${{ steps.import-secrets.outputs.ART_ARTIFACTORY_PASSWORD }} % "generic/trokk/${{ github.ref_name }}/"
xargs -I % jf rt u --url ${{ steps.import-secrets.outputs.ART_ARTIFACTORY_URL }} --user ${{ steps.import-secrets.outputs.ART_ARTIFACTORY_USER }} --password ${{ steps.import-secrets.outputs.ART_ARTIFACTORY_PASSWORD }} % "generic/trokk/${{ github.ref_name }}/"
5 changes: 4 additions & 1 deletion .github/workflows/rust-check-pull.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ jobs:
OIDC_BASE_URL: "placeholder"
OIDC_CLIENT_ID: "placeholder"
OIDC_CLIENT_SECRET: "placeholder"
OIDC_TEKST_BASE_URL: "placeholder"
OIDC_TEKST_CLIENT_ID: "placeholder"
OIDC_TEKST_CLIENT_SECRET: "placeholder"
steps:
- uses: actions/checkout@v4
- name: Install dependencies (ubuntu only)
Expand All @@ -32,4 +35,4 @@ jobs:
run: cargo clippy --all -- -D warnings
- name: Run tests
if: always()
run: cargo test --all
run: cargo test --all
15 changes: 9 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,15 @@ Appen er nå hardkodet til å hente filer fra ```$DOCUMENT/trokk/files```, så l

Sett disse environment variablene for å få appen til å fungere:

| Variabel | Beskrivelse |
|----------------------|------------------------------------------------------------|
| `PAPI_PATH` | URL til API'et vi sender registreringen til. |
| `OIDC_BASE_URL` | URL til OIDC server (inkludert "protocol/openid-connect"). |
| `OIDC_CLIENT_ID` | Client ID til OIDC server. |
| `OIDC_CLIENT_SECRET` | Client secret til OIDC server. |
| Variabel | Beskrivelse |
|----------------------------|--------------------------------------------------------------------------------------|
| `PAPI_PATH` | URL til API'et vi sender registreringen til. |
| `OIDC_BASE_URL` | URL til OIDC server (nbauth-realm, inkludert "protocol/openid-connect"). |
| `OIDC_CLIENT_ID` | Client ID til OIDC server (nbauth-realm) |
| `OIDC_CLIENT_SECRET` | Client secret til OIDC server (nbauth-realm) |
| `OIDC_TEKST_BASE_URL` | URL til OIDC server for papi auth (tekst-realm, inkludert "protocol/openid-connect") |
| `OIDC_TEKST_CLIENT_ID` | Client ID til OIDC server (tekst-realm) |
| `OIDC_TEKST_CLIENT_SECRET` | Client secret til OIDC server (tekst-realm) |


## Vedlikehold
Expand Down
26 changes: 25 additions & 1 deletion src-tauri/src/auth.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
use std::borrow::Cow;
use std::collections::HashMap;
use std::error::Error;
use std::time::{SystemTime, UNIX_EPOCH};

use reqwest::Client;
use tauri::Window;
use tauri_plugin_oauth::{start_with_config, OauthConfig};
use url::Url;

use crate::model::{AuthenticationResponse, ExpireInfo, TokenResponse, UserInfo};
use crate::model::{
AuthenticationResponse, ExpireInfo, TokenResponse, TokenResponseWithoutRefresh, UserInfo,
};
use crate::ENVIRONMENT_VARIABLES;

pub(crate) fn log_in_with_server_redirect(window: Window) -> Result<u16, String> {
Expand Down Expand Up @@ -59,6 +62,27 @@ pub(crate) async fn refresh_token(refresh_token: String) -> AuthenticationRespon
create_token(client, body).await
}

pub(crate) async fn get_access_token_for_papi() -> Result<String, Box<dyn Error>> {
let client = Client::new();
let body = format!(
"client_id={}&client_secret={}&grant_type=client_credentials",
ENVIRONMENT_VARIABLES.oidc_tekst_client_id, ENVIRONMENT_VARIABLES.oidc_tekst_client_secret
);

let res = client
.post(format!(
"{}{}",
ENVIRONMENT_VARIABLES.oidc_tekst_base_url, "/token"
))
.header("Content-Type", "application/x-www-form-urlencoded")
.body(body)
.send()
.await;

let token_response: TokenResponseWithoutRefresh = serde_json::from_str(&res?.text().await?)?;
Ok(token_response.access_token)
}

async fn create_token(client: Client, body: String) -> AuthenticationResponse {
let time_now = SystemTime::now()
.duration_since(UNIX_EPOCH)
Expand Down
13 changes: 12 additions & 1 deletion src-tauri/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ pub static ENVIRONMENT_VARIABLES: RequiredEnvironmentVariables = RequiredEnviron
oidc_base_url: env!("OIDC_BASE_URL"),
oidc_client_id: env!("OIDC_CLIENT_ID"),
oidc_client_secret: env!("OIDC_CLIENT_SECRET"),
oidc_tekst_base_url: env!("OIDC_TEKST_BASE_URL"),
oidc_tekst_client_id: env!("OIDC_TEKST_CLIENT_ID"),
oidc_tekst_client_secret: env!("OIDC_TEKST_CLIENT_SECRET"),
};

#[tauri::command]
Expand Down Expand Up @@ -87,6 +90,13 @@ async fn pick_directory(start_path: String) -> Result<String, String> {
file_utils::directory_picker(start_path).await
}

#[tauri::command]
async fn get_papi_access_token() -> Result<String, String> {
auth::get_access_token_for_papi()
.await
.map_err(|e| format!("Could not get token for Papi. {e:?}"))
}

fn main() {
tauri::Builder::default()
.plugin(tauri_plugin_store::Builder::default().build())
Expand All @@ -105,7 +115,8 @@ fn main() {
get_total_size_of_files_in_folder,
copy_dir,
delete_dir,
pick_directory
pick_directory,
get_papi_access_token
])
.system_tray(system_tray::get_system_tray())
.on_system_tray_event(system_tray::system_tray_event_handler())
Expand Down
17 changes: 17 additions & 0 deletions src-tauri/src/model.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,28 @@ pub(crate) struct UserInfo {
email: String,
}

#[derive(Debug, Deserialize, Serialize, Clone)]
pub(crate) struct TokenResponseWithoutRefresh {
#[serde(rename(serialize = "accessToken", deserialize = "access_token"))]
pub(crate) access_token: String,
#[serde(rename(serialize = "expiresIn", deserialize = "expires_in"))]
pub(crate) expires_in: i32,
#[serde(rename(serialize = "tokenType", deserialize = "token_type"))]
token_type: String,
#[serde(rename(serialize = "notBeforePolicy", deserialize = "not-before-policy"))]
// NB! Special kebab-case from OIDC-server
not_before_policy: i32,
scope: String,
}

#[derive(Debug, Deserialize, Serialize, Clone)]
#[serde(rename_all = "camelCase")]
pub struct RequiredEnvironmentVariables {
pub(crate) papi_path: &'static str,
pub(crate) oidc_base_url: &'static str,
pub(crate) oidc_client_id: &'static str,
pub(crate) oidc_client_secret: &'static str,
pub(crate) oidc_tekst_base_url: &'static str,
pub(crate) oidc_tekst_client_id: &'static str,
pub(crate) oidc_tekst_client_secret: &'static str,
}
11 changes: 9 additions & 2 deletions src/lib/RegistrationSchema.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -55,10 +55,17 @@
return Promise.reject(error)
})
return fetch(`${papiPath}/item/`,
const accessToken = await invoke("get_papi_access_token")
.catch(error => {
deleteDir(newPath!)
handleError('Kunne ikke hente tilgangsnøkkel for å lagre objektet i databasen.')
return Promise.reject(error)
})
return fetch(`${papiPath}/item`,
{
method: 'POST',
headers: {"Authorization" : "Bearer " + auth.tokenResponse.accessToken},
headers: {"Authorization" : "Bearer " + accessToken},
body: Body.json(new TextInputDto(
materialType ?? "",
fraktur ? "FRAKTUR" : "ANTIQUA",
Expand Down
24 changes: 24 additions & 0 deletions src/test/RegistrationSchema.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ describe('RegistrationSchema.svelte', () => {
case 'get_total_size_of_files_in_folder': return Promise.resolve(BigInt(123))
case 'copy_dir': return Promise.resolve('/scanner/123abc')
case 'delete_dir': return Promise.resolve()
case 'get_papi_access_token': return Promise.resolve('token')
case 'tauri': {
if (args['__tauriModule'] === 'Http') { // fetch requests has cmd=tauri and args.__tauriModule=Http
return Promise.resolve(textInputDtoResponseMockNewspaper)
Expand Down Expand Up @@ -102,6 +103,16 @@ describe('RegistrationSchema.svelte', () => {
expect(hostNameSpy).toHaveBeenCalledWith(expect.objectContaining({cmd: 'get_total_size_of_files_in_folder'}))
})

test('registration should get access token for PAPI', async () => {
const tokenSpy = vi.spyOn(window, '__TAURI_IPC__')
expect(tokenSpy).not.toHaveBeenCalled()

container.getByText('TRØKK!').click()

await new Promise(resolve => setTimeout(resolve, 0))
expect(tokenSpy).toHaveBeenCalledWith(expect.objectContaining({cmd: 'get_papi_access_token'}))
})

test('registration should post to papi with correct params', async () => {
const hostNameSpy = vi.spyOn(window, '__TAURI_IPC__')
expect(hostNameSpy).not.toHaveBeenCalled()
Expand Down Expand Up @@ -180,6 +191,19 @@ describe('RegistrationSchema.svelte', () => {
expect(res).toBeTruthy()
})

test('registration should show error message if get token for papi failed', async () => {
mockIPC((cmd) => {
if (cmd === 'get_papi_access_token') return Promise.reject('token failed')
else return ''
})

container.getByText('TRØKK!').click()

await new Promise(resolve => setTimeout(resolve, 0))
const res = container.getByText('Kunne ikke hente tilgangsnøkkel for å lagre objektet i databasen', {exact: false})
expect(res).toBeTruthy()
})

test('registration should show error message if papi post failed', async () => {
mockIPC((cmd) => {
if (cmd === 'tauri') return Promise.reject('cannot post to papi')
Expand Down

0 comments on commit 591b4d0

Please sign in to comment.