diff --git a/docker-compose.yml b/docker-compose.yml index d7d6047ba..91cb4fcd2 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -30,8 +30,8 @@ services: - ERRORS_HANDLERS_REDIRECT_CONFIG_TO=http://accounts.flock.local:8081/ui/login - MUTATORS_ID_TOKEN_CONFIG_ISSUER_URL=http://accounts.flock.local:8081 - SERVE_PROXY_CORS_ALLOWED_ORIGINS_0=http://workday.flock.local:8081 - - SERVE_PROXY_CORS_ALLOWED_ORIGINS_1=http://accounts.flock.local:8081/ui/ - - SERVE_PROXY_CORS_ALLOWED_ORIGINS_2=http://accounts.flock.local:8081/api + - SERVE_PROXY_CORS_ALLOWED_ORIGINS_1=http://accounts.flock.local:8081 + - SERVE_PROXY_CORS_ALLOWED_ORIGINS_2=http://fe-workday.flock.local:8081 restart: on-failure networks: - intranet @@ -51,8 +51,9 @@ services: - SERVE_PUBLIC_BASE_URL=http://accounts.flock.local:8081/api - SERVE_ADMIN_BASE_URL=http://kratos:4434 - SELFSERVICE_DEFAULT_BROWSER_RETURN_URL=http://workday.flock.local:8081 - - SELFSERVICE_ALLOWED_RETURN_URLS_0=http://workday.flock.local:8081 - - SELFSERVICE_ALLOWED_RETURN_URLS_1=http://accounts.flock.local:8081/ui/ + - SELFSERVICE_ALLOWED_RETURN_URLS_0=http://accounts.flock.local:8081 + - SELFSERVICE_ALLOWED_RETURN_URLS_1=http://workday.flock.local:8081 + - SELFSERVICE_ALLOWED_RETURN_URLS_2=http://fe-workday.flock.local:8081 # - BASE_PATH=/kratos - SELFSERVICE_FLOWS_ERROR_UI_URL=http://accounts.flock.local:8081/ui/error - SELFSERVICE_FLOWS_SETTINGS_UI_URL=http://accounts.flock.local:8081/ui/settings diff --git a/docker/oathkeeper/rules/admin.yaml b/docker/oathkeeper/rules/admin.yaml index 0020ec7b4..7d5439d03 100644 --- a/docker/oathkeeper/rules/admin.yaml +++ b/docker/oathkeeper/rules/admin.yaml @@ -99,7 +99,7 @@ - id: keto-admin-ui version: v0.40.2 upstream: - url: http://host.docker.internal:3000 + url: http://host.docker.internal:3001 match: url: http://accounts.flock.local:8081/keto-ui/<.*> methods: diff --git a/docker/oathkeeper/rules/rules.yaml b/docker/oathkeeper/rules/rules.yaml index 817271c33..c26dd628c 100644 --- a/docker/oathkeeper/rules/rules.yaml +++ b/docker/oathkeeper/rules/rules.yaml @@ -5,7 +5,7 @@ url: http://host.docker.internal:8080 version: v0.40.2 match: - url: http://workday.flock.local:8081/<(api|login).*> + url: http://<(fe-)?>workday.flock.local:<3000|8081>/<(api|login).*> methods: - GET - POST @@ -13,33 +13,69 @@ - DELETE authenticators: - handler: cookie_session + authorizer: + handler: remote_json + config: + payload: | + { + "namespace": "Person", + "object": "{{ .MatchContext.Header.Get "Context-Person-Id" }}", + "relation": "view", + "subject_set" : { + "namespace": "User", + "object": "{{print .Subject}}", + "relation": "" + } + } + mutators: + - handler: header + - handler: id_token + errors: + - handler: redirect + +- id: workday-api-call-bootstrap + upstream: + # url: http://workday:8080 + # to allow to use 'local' app rather than docker one + url: http://host.docker.internal:8080 + version: v0.40.2 + match: + url: http://<(fe-)?>workday.flock.local:8081/bootstrap + methods: + - GET + authenticators: + - handler: cookie_session authorizer: handler: allow -# handler: remote_json -# config: -# payload: | -# { -# "namespace": "Person", -# "object": "{{ .MatchContext.Header.Get "Context-Person-Id" }}", -# "relation": "view", -# "subject_set" : { -# "namespace": "User", -# "object": "{{print .Subject}}", -# "relation": "" -# } -# } mutators: - handler: header - handler: id_token -# config: -# claims: | -# { -# "aud": ["http://workday.flock.local:8081"], -# "email": "{{ print .Extra.identity.traits.email }}" -# } errors: - handler: redirect + +- id: workday-fe-resources-react + upstream: + # url: http://workday:8080 + # to allow to use 'local' app rather than docker one + url: http://host.docker.internal:3000 + version: v0.40.2 + match: + # all urls not starting with /api or /login + url: http://fe-workday.flock.local:8081/<(?!(api|login|bootstrap)).*> + methods: + - GET + authenticators: + - handler: cookie_session + authorizer: + handler: allow + mutators: + - handler: header + - handler: id_token + errors: + - handler: redirect + + - id: workday-fe-resources upstream: # url: http://workday:8080 @@ -48,7 +84,7 @@ version: v0.40.2 match: # all urls not starting with /api or /login - url: http://workday.flock.local:8081/<(?!(api|login)).*> + url: http://workday.flock.local:8081/<(?!(api|login|bootstrap)).*> methods: - GET authenticators: @@ -58,11 +94,5 @@ mutators: - handler: header - handler: id_token -# config: -# claims: | -# { -# "aud": ["http://workday.flock.local:8081"], -# "email": "{{ print .Extra.identity.traits.email }}" -# } errors: - handler: redirect diff --git a/docs/identity-access-management.md b/docs/identity-access-management.md index 460988e29..528a72293 100644 --- a/docs/identity-access-management.md +++ b/docs/identity-access-management.md @@ -60,8 +60,7 @@ Which can be read as > ℹ️ > This model allows manager of (a) Flock. to have a relation with a specific Workday coupled to a person. > -> E.g. _Workday-X_ is **owned** by _Person-Y_, which is part of **organisational unit** _Flock-Z_, which in turn is \* -> \*managed\*\* by _User-manager-A_ +> E.g. _Workday-X_ is **owned** by _Person-Y_, which is part of **organisational unit** _Flock-Z_, which in turn is \* > \*managed\*\* by _User-manager-A_ Besides the relations model, Workday also need permissions assigned. Ory's keto, provided an intuitive concept for permissions in the following form: @@ -83,11 +82,12 @@ for the implementation details see [permissions.ts](../docker/keto/namespaces/pe > ℹ️ Prerequisites: > -> 1. In your `etc/hosts`, the domains `accounts.flock.local` and `workday.flock.local` should both resolve to 127.0.0.1 +> 1. In your `etc/hosts`, the domains `accounts.flock.local`, `fe-workday.flock.local` and `workday.flock.local` should both resolve to 127.0.0.1 > > ``` > 127.0.0.1 accounts.flock.local > 127.0.0.1 workday.flock.local +> 127.0.0.1 fe-workday.flock.local > ``` > > 2. Run `docker compose up -d` to start all Ory related containers for identity and access management. diff --git a/src/develop/kotlin/community/flock/eco/workday/mocks/KratosClient.kt b/src/develop/kotlin/community/flock/eco/workday/mocks/KratosClient.kt index 21b776eb0..463822ded 100644 --- a/src/develop/kotlin/community/flock/eco/workday/mocks/KratosClient.kt +++ b/src/develop/kotlin/community/flock/eco/workday/mocks/KratosClient.kt @@ -56,7 +56,7 @@ class KratosClient( CreateKratosIdentity.Traits.Name(firstName, lastName), email ), - credentials = CreateKratosIdentity.Credentials.passwordCredentials(firstName), + credentials = CreateKratosIdentity.Credentials.passwordCredentials(firstName.lowercase()), verifiableAddresses = listOf( CreateKratosIdentity.Address( value = email, diff --git a/src/main/kotlin/ApplicationConfiguration.kt b/src/main/kotlin/ApplicationConfiguration.kt index 1417622b6..012fc0bc9 100644 --- a/src/main/kotlin/ApplicationConfiguration.kt +++ b/src/main/kotlin/ApplicationConfiguration.kt @@ -13,7 +13,7 @@ import org.springframework.web.servlet.config.annotation.EnableWebMvc @Configuration @EnableJpaRepositories -@EnableWebMvc +//@EnableWebMvc @EntityScan @ComponentScan( basePackages = [ @@ -22,6 +22,7 @@ import org.springframework.web.servlet.config.annotation.EnableWebMvc "community.flock.eco.workday.controllers", "community.flock.eco.workday.mappers", "community.flock.eco.workday.google", + "community.flock.eco.workday.authentication", ] ) @Import( diff --git a/src/main/kotlin/config/WebMvcConfig.kt b/src/main/kotlin/config/WebMvcConfig.kt index 01830d790..ebeb91a97 100644 --- a/src/main/kotlin/config/WebMvcConfig.kt +++ b/src/main/kotlin/config/WebMvcConfig.kt @@ -2,13 +2,11 @@ package community.flock.eco.workday.config import org.springframework.core.io.ClassPathResource import org.springframework.core.io.Resource -import org.springframework.web.servlet.config.annotation.EnableWebMvc import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry import org.springframework.web.servlet.config.annotation.WebMvcConfigurer import org.springframework.web.servlet.resource.PathResourceResolver import java.io.IOException -@EnableWebMvc class WebMvcConfig : WebMvcConfigurer { override fun addResourceHandlers(registry: ResourceHandlerRegistry) { diff --git a/src/main/react/hooks/StatusHook.js b/src/main/react/hooks/StatusHook.js index 52cb9c551..48b8b231c 100644 --- a/src/main/react/hooks/StatusHook.js +++ b/src/main/react/hooks/StatusHook.js @@ -1,7 +1,8 @@ import { useEffect, useState } from "react"; import { BootstrapClient } from "../clients/BootstrapClient"; -let store = null; +// eslint-disable-next-line import/no-mutable-exports +export let store = null; const listeners = []; function update(it) { @@ -19,7 +20,11 @@ export function useLoginStatus() { } listeners.push(listener); return () => { - listeners.filter((it) => it !== listener); + const index = listeners.indexOf(listener); + if (index !== -1) { + // Remove setState at cleanup + listeners.splice(index, 1); + } }; }, []); diff --git a/src/main/react/index.js b/src/main/react/index.js index 1819d4933..a90fe87e5 100644 --- a/src/main/react/index.js +++ b/src/main/react/index.js @@ -1,19 +1,19 @@ import React from "react"; import ReactDOM from "react-dom"; import { Application } from "./application/Application.tsx"; -import {store as personStore } from "./hooks/PersonHook"; +import { store } from "./hooks/StatusHook"; const { fetch: originalFetch } = window; window.fetch = async (...args) => { - const [resource, config ] = args; + const [resource, config] = args; const opts = { ...config, - headers:{ - "Context-Person-Id": personStore?.id, - ...config?.headers + headers: { + "Context-Person-Id": store && store.personId, + ...config.headers, }, - } + }; const response = await originalFetch(resource, opts); return response; }; diff --git a/webpack.config.js b/webpack.config.js index 21a24ea55..867d2ad54 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -20,13 +20,18 @@ const config = { devServer: { ...ecoConfig.devServer, historyApiFallback: true, + // TODO: create separate config to do local development with the Ory stack + host: '0.0.0.0', // needed for the Ory stack + disableHostCheck: true, // needed for the Ory stack proxy: { ...ecoConfig.devServer.proxy, - "/bootstrap": "http://localhost:8080", - "/logout": "http://localhost:8080", - "/tasks/*": "http://localhost:8080", - "/export/*": "http://localhost:8080", - "/oauth2/*": "http://localhost:8080", + "/api": "http://workday.flock.local:8081", + "/login": "http://workday.flock.local:8081", + "/bootstrap": "http://workday.flock.local:8081", + "/logout": "http://workday.flock.local:8081", + "/tasks/*": "http://workday.flock.local:8081", + "/export/*": "http://workday.flock.local:8081", + "/oauth2/*": "http://workday.flock.local:8081", }, }, };