Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tech - Ajout de keycloak et sécurisation des APIs (UPDATE ENV VAR) #3501

Merged
merged 8 commits into from
Aug 14, 2024
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ init-local-sig:
./infra/local/postgis_insert_layers.sh && ./infra/init/geoserver_init_layers.sh

run-back: run-stubbed-apis
docker compose up -d --quiet-pull --wait db
docker compose up -d --quiet-pull --wait db keycloak
cd backend && ./gradlew bootRun --args='--spring.profiles.active=local --spring.config.additional-location=$(INFRA_FOLDER)'

run-back-with-monitorenv: run-monitorenv
Expand Down Expand Up @@ -154,15 +154,15 @@ docker-compose-up:
docker compose -f ./infra/docker/docker-compose.cypress.yml up --quiet-pull flyway
docker compose -f ./infra/docker/docker-compose.cypress.yml up -d --quiet-pull app
@printf 'Waiting for backend app to be ready'
@until curl --output /dev/null --silent --fail "http://localhost:8880/bff/v1/healthcheck"; do printf '.' && sleep 1; done
@until curl --output /dev/null --silent --fail "http://localhost:8880/api/v1/healthcheck"; do printf '.' && sleep 1; done

docker-compose-puppeteer-up: docker-env
docker compose -f ./infra/docker/docker-compose.puppeteer.yml up -d monitorenv-app
docker compose -f ./infra/docker/docker-compose.puppeteer.yml up -d monitorfish-app
@printf 'Waiting for MonitorEnv app to be ready'
@until curl --output /dev/null --silent --fail "http://localhost:9880/bff/v1/healthcheck"; do printf '.' && sleep 1; done
@until curl --output /dev/null --silent --fail "http://localhost:9880/api/v1/healthcheck"; do printf '.' && sleep 1; done
@printf 'Waiting for MonitorFish app to be ready'
@until curl --output /dev/null --silent --fail "http://localhost:8880/bff/v1/healthcheck"; do printf '.' && sleep 1; done
@until curl --output /dev/null --silent --fail "http://localhost:8880/api/v1/healthcheck"; do printf '.' && sleep 1; done

# ----------------------------------------------------------
# CI: Pipeline Commands
Expand Down
louptheron marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ class FleetSegmentController(
}
}

@PutMapping(value = [""], consumes = ["application/json"])
@PutMapping(value = ["/backoffice"], consumes = ["application/json"])
@Operation(summary = "Update a fleet segment")
fun updateFleetSegment(
@Parameter(description = "Year")
Expand All @@ -56,7 +56,7 @@ class FleetSegmentController(
return FleetSegmentDataOutput.fromFleetSegment(updatedFleetSegment)
}

@DeleteMapping(value = [""])
@DeleteMapping(value = ["/backoffice"])
@Operation(summary = "Delete a fleet segment")
fun deleteFleetSegment(
@Parameter(description = "Year")
Expand All @@ -72,7 +72,7 @@ class FleetSegmentController(
}

@ResponseStatus(HttpStatus.CREATED)
@PostMapping(value = [""])
@PostMapping(value = ["/backoffice"])
@Operation(summary = "Create a fleet segment")
fun createFleetSegment(
@RequestBody
Expand All @@ -83,14 +83,14 @@ class FleetSegmentController(
return FleetSegmentDataOutput.fromFleetSegment(createdFleetSegment)
}

@GetMapping("/years")
@GetMapping("/backoffice/years")
@Operation(summary = "Get fleet segment year entries")
fun getFleetSegmentYearEntries(): List<Int> {
return getFleetSegmentYearEntries.execute()
}

@ResponseStatus(HttpStatus.CREATED)
@PostMapping("/{year}")
@PostMapping("/backoffice/{year}")
@Operation(summary = "Add a fleet segment year")
fun addFleetSegmentYear(
@PathParam("Year")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ class FleetSegmentControllerITests {

// When
api.perform(
put("/bff/v1/fleet_segments?year=2021&segment=A_SEGMENT/WITH/SLASH")
put("/bff/v1/fleet_segments/backoffice?year=2021&segment=A_SEGMENT/WITH/SLASH")
.content(
objectMapper.writeValueAsString(CreateOrUpdateFleetSegmentDataInput(gears = listOf("OTB", "OTC"))),
)
Expand All @@ -113,15 +113,15 @@ class FleetSegmentControllerITests {
@Test
fun `Should return Ok When a delete of a fleet segment is done`() {
// When
api.perform(delete("/bff/v1/fleet_segments?year=2021&segment=A_SEGMENT/WITH/SLASH"))
api.perform(delete("/bff/v1/fleet_segments/backoffice?year=2021&segment=A_SEGMENT/WITH/SLASH"))
// Then
.andExpect(status().isOk)
}

@Test
fun `Should return Ok When a new year is created`() {
// When
api.perform(post("/bff/v1/fleet_segments/2023"))
api.perform(post("/bff/v1/fleet_segments/backoffice/2023"))
// Then
.andExpect(status().isCreated)
}
Expand All @@ -136,7 +136,7 @@ class FleetSegmentControllerITests {

// When
api.perform(
post("/bff/v1/fleet_segments")
post("/bff/v1/fleet_segments/backoffice")
.content(
objectMapper.writeValueAsString(
CreateOrUpdateFleetSegmentDataInput(
Expand Down Expand Up @@ -164,7 +164,7 @@ class FleetSegmentControllerITests {

// When
api.perform(
post("/bff/v1/fleet_segments")
post("/bff/v1/fleet_segments/backoffice")
.content(
objectMapper.writeValueAsString(
CreateOrUpdateFleetSegmentDataInput(segment = "SEGMENT", gears = listOf("OTB", "OTC")),
Expand Down
8 changes: 8 additions & 0 deletions datascience/docs/source/contributing.rst
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,14 @@ To run the backend for development purpose (with hot-reload), open another termi
* During the first run, dependencies will be downloaded
* You'll need to install `psql` to interact with the Postgres database

The users for login are:
- User with non super-user access:
- username: "user"
- password: "fish"
- User with super-user access:
- username: "superuser"
- password: "fish"

Then, insert the GIS layers to the postgres database by executing (make sure you have `psql` installed):

.. code-block:: shell
Expand Down
14 changes: 14 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,20 @@ services:
volumes:
- ./frontend/cypress/mappings:/home/wiremock/mappings

keycloak:
container_name: monitorfish_keycloak
image: quay.io/keycloak/keycloak:latest
environment:
- KEYCLOAK_ADMIN=admin
- KEYCLOAK_ADMIN_PASSWORD=admin
ports:
- "8085:8080"
volumes:
- ./infra/dev/keycloak:/opt/keycloak/data/import
command:
- start-dev
- --import-realm

volumes:
geoserver-data:
driver: local
Expand Down
1 change: 1 addition & 0 deletions frontend/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ FRONTEND_OIDC_AUTHORITY=
FRONTEND_OIDC_CLIENT_ID=
FRONTEND_OIDC_ENABLED=
FRONTEND_OIDC_REDIRECT_URI=
FRONTEND_OIDC_LOGOUT_REDIRECT_URI=

################################################################################
# Sentry
Expand Down
7 changes: 4 additions & 3 deletions frontend/.env.local.defaults
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,11 @@ FRONTEND_MONITORENV_URL=//localhost:8081
################################################################################
# OICD

FRONTEND_OIDC_AUTHORITY=https://authentification.recette.din.developpement-durable.gouv.fr/authSAML/oidc/monitorfish
FRONTEND_OIDC_AUTHORITY=http://localhost:8085/realms/monitor
FRONTEND_OIDC_CLIENT_ID=monitorfish
FRONTEND_OIDC_ENABLED=false
FRONTEND_OIDC_REDIRECT_URI=https://monitorfish.din.developpement-durable.gouv.fr
FRONTEND_OIDC_ENABLED=true
FRONTEND_OIDC_REDIRECT_URI=http://localhost:3000
FRONTEND_OIDC_LOGOUT_REDIRECT_URI=http://localhost:3000

################################################################################
# Sentry
Expand Down
8 changes: 5 additions & 3 deletions frontend/cypress/e2e/backoffice/fleet_segments.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ context('Fleet segments', () => {
cy.log('Should update the segment')

// When
cy.intercept('PUT', `/bff/v1/fleet_segments?year=${currentYear}&segment=ATL01`).as('updateFleetSegment')
cy.intercept('PUT', `/bff/v1/fleet_segments/backoffice?year=${currentYear}&segment=ATL01`).as('updateFleetSegment')

cy.get('[aria-rowindex="2"]').find('[title="Editer la ligne"]').click()
cy.fill('Nom', 'ATL036')
Expand Down Expand Up @@ -92,7 +92,7 @@ context('Fleet segments', () => {

it('Should create a new fleet segment and delete it', () => {
// Given
cy.intercept('POST', '/bff/v1/fleet_segments').as('createFleetSegment')
cy.intercept('POST', '/bff/v1/fleet_segments/backoffice').as('createFleetSegment')

// When
cy.clickButton('Ajouter un segment')
Expand Down Expand Up @@ -137,7 +137,9 @@ context('Fleet segments', () => {
// -------------------------------------------------------------------------
cy.log('Should delete a fleet segment')

cy.intercept('DELETE', `/bff/v1/fleet_segments?year=${currentYear}&segment=ABC123`).as('deleteFleetSegment')
cy.intercept('DELETE', `/bff/v1/fleet_segments/backoffice?year=${currentYear}&segment=ABC123`).as(
'deleteFleetSegment'
)
cy.get('[aria-rowindex="2"]').find('[title="Supprimer la ligne"]').click()
cy.wait('@deleteFleetSegment')

Expand Down
3 changes: 2 additions & 1 deletion frontend/src/auth/getOIDCConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ const IS_CYPRESS = isCypress()
export function getOIDCConfig() {
const IS_OIDC_ENABLED = import.meta.env.FRONTEND_OIDC_ENABLED === 'true'
const OIDC_REDIRECT_URI = import.meta.env.FRONTEND_OIDC_REDIRECT_URI
const OIDC_LOGOUT_REDIRECT_URI = import.meta.env.FRONTEND_OIDC_LOGOUT_REDIRECT_URI
const OIDC_AUTHORITY = import.meta.env.FRONTEND_OIDC_AUTHORITY
const OIDC_CLIENT_ID = import.meta.env.FRONTEND_OIDC_CLIENT_ID

Expand All @@ -21,7 +22,7 @@ export function getOIDCConfig() {
authority: String(OIDC_AUTHORITY),
client_id: String(OIDC_CLIENT_ID),
onSigninCallback,
post_logout_redirect_uri: 'https://www.mer.gouv.fr',
post_logout_redirect_uri: String(OIDC_LOGOUT_REDIRECT_URI),
redirect_uri: String(OIDC_REDIRECT_URI),
scope: 'openid email',
userStore: new WebStorageStateStore({ store: window.localStorage })
Expand Down
1 change: 1 addition & 0 deletions frontend/src/env.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ interface ImportMetaEnv {
readonly FRONTEND_OIDC_AUTHORITY: string
readonly FRONTEND_OIDC_CLIENT_ID: string
readonly FRONTEND_OIDC_ENABLED: string
readonly FRONTEND_OIDC_LOGOUT_REDIRECT_URI: string
readonly FRONTEND_OIDC_REDIRECT_URI: string
readonly FRONTEND_PRIOR_NOTIFICATION_LIST_ENABLED: string
readonly FRONTEND_SENTRY_DSN?: string
Expand Down
10 changes: 5 additions & 5 deletions frontend/src/features/FleetSegment/apis.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ async function updateFleetSegmentFromAPI(
): Promise<FleetSegment> {
try {
return await monitorfishApiKy
.put(`/bff/v1/fleet_segments?year=${year}&segment=${segment}`, {
.put(`/bff/v1/fleet_segments/backoffice?year=${year}&segment=${segment}`, {
json: updatedFields
})
.json<FleetSegment>()
Expand All @@ -70,7 +70,7 @@ async function updateFleetSegmentFromAPI(
async function deleteFleetSegmentFromAPI(segment: string, year: number): Promise<FleetSegment[]> {
try {
return await monitorfishApiKy
.delete(`/bff/v1/fleet_segments?year=${year}&segment=${segment}`)
.delete(`/bff/v1/fleet_segments/backoffice?year=${year}&segment=${segment}`)
.json<FleetSegment[]>()
} catch (err) {
throw new ApiError(DELETE_FLEET_SEGMENT_ERROR_MESSAGE, err)
Expand All @@ -85,7 +85,7 @@ async function deleteFleetSegmentFromAPI(segment: string, year: number): Promise
async function createFleetSegmentFromAPI(segmentFields: UpdateFleetSegment): Promise<FleetSegment> {
try {
return await monitorfishApiKy
.post('/bff/v1/fleet_segments', {
.post('/bff/v1/fleet_segments/backoffice', {
json: segmentFields
})
.json<FleetSegment>()
Expand All @@ -101,7 +101,7 @@ async function createFleetSegmentFromAPI(segmentFields: UpdateFleetSegment): Pro
*/
async function addFleetSegmentYearFromAPI(nextYear: number) {
try {
return await monitorfishApiKy.post(`/bff/v1/fleet_segments/${nextYear}`)
return await monitorfishApiKy.post(`/bff/v1/fleet_segments/backoffice/${nextYear}`)
} catch (err) {
throw new ApiError(ADD_FLEET_SEGMENT_YEAR_ERROR_MESSAGE, err)
}
Expand All @@ -114,7 +114,7 @@ async function addFleetSegmentYearFromAPI(nextYear: number) {
*/
async function getFleetSegmentYearEntriesFromAPI(): Promise<number[]> {
try {
return await monitorfishApiKy.get('/bff/v1/fleet_segments/years').json<number[]>()
return await monitorfishApiKy.get('/bff/v1/fleet_segments/backoffice/years').json<number[]>()
} catch (err) {
throw new ApiError(GET_FLEET_SEGMENT_YEAR_ENTRIES_ERROR_MESSAGE, err)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { fleetSegmentApi } from '@features/FleetSegment/apis'
import type { FleetSegment } from '@features/FleetSegment/types'
import type { MissionActionFormValues } from '@features/Mission/components/MissionForm/types'

export const getFleetSegments =
export const computeFleetSegments =
(
faoAreas: string[] | undefined,
gearOnBoard: MissionActionFormValues['gearOnboard'],
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { MissionAction } from '@features/Mission/missionAction.types'

import { getFleetSegments } from '../../../../../domain/use_cases/vessel/getFleetSegments'
import { computeFleetSegments } from '../../../../FleetSegment/useCases/computeFleetSegments'

import type { MissionActionFormValues } from '@features/Mission/components/MissionForm/types'
import type { Option } from '@mtes-mct/monitor-ui'
Expand All @@ -17,7 +17,7 @@ export const updateActionSegments =
}

const computedFleetSegments = await dispatch(
getFleetSegments(missionAction.faoAreas, missionAction.gearOnboard, missionAction.speciesOnboard)
computeFleetSegments(missionAction.faoAreas, missionAction.gearOnboard, missionAction.speciesOnboard)
)

const nextFleetSegments = fleetSegmentsAsOptions
Expand Down
2 changes: 1 addition & 1 deletion infra/configurations/application-dev.properties
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ monitorfish.oidc.userinfo-endpoint=/api/user

monitorfish.api.protected.paths=/bff/*,/light/v1/vessels/*
# Super-user paths of type /** are not supported
monitorfish.api.protected.super-user-paths=/bff/v1/beacon_malfunctions,/bff/v1/missions,/bff/v1/operational_alerts,/bff/v1/reportings,/bff/v1/vessels/risk_factors
monitorfish.api.protected.super-user-paths=/bff/v1/beacon_malfunctions,/bff/v1/missions,/bff/v1/operational_alerts,/bff/v1/reportings,/bff/v1/vessels/risk_factors,/bff/v1/control_objectives,/bff/v1/fleet_segments/backoffice,/bff/v1/fleet_segments/compute
monitorfish.api.protected.public-paths=/api/v1/authorization/management/*,/api/v1/beacon_malfunctions/*,/api/v1/mission_actions/*

###################
Expand Down
8 changes: 4 additions & 4 deletions infra/configurations/application-local.properties
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,13 @@ spring.main.lazy-initialization=true
monitorfish.sentry.enabled=false
sentry.dsn=

monitorfish.oidc.enabled=false
monitorfish.oidc.issuer-uri=https://authentification.recette.din.developpement-durable.gouv.fr/authSAML/oidc/monitorfish
monitorfish.oidc.userinfo-endpoint=/api/user
monitorfish.oidc.enabled=true
monitorfish.oidc.issuer-uri=http://localhost:8085/realms/monitor
monitorfish.oidc.userinfo-endpoint=/protocol/openid-connect/userinfo

monitorfish.api.protected.paths=/bff/*,/light/v1/vessels/*
# Super-user paths of type /** are not supported
monitorfish.api.protected.super-user-paths=/bff/v1/beacon_malfunctions,/bff/v1/missions,/bff/v1/operational_alerts,/bff/v1/reportings,/bff/v1/vessels/risk_factors
monitorfish.api.protected.super-user-paths=/bff/v1/beacon_malfunctions,/bff/v1/missions,/bff/v1/operational_alerts,/bff/v1/reportings,/bff/v1/vessels/risk_factors,/bff/v1/control_objectives,/bff/v1/fleet_segments/backoffice,/bff/v1/fleet_segments/compute
monitorfish.api.protected.public-paths=/api/v1/authorization/management/*,/api/v1/beacon_malfunctions/*,/api/v1/mission_actions/*
monitorfish.api.protected.api-key=DUMMY-API-KEY

Expand Down
2 changes: 1 addition & 1 deletion infra/configurations/application-prod.properties
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ monitorfish.oidc.userinfo-endpoint=/api/user

monitorfish.api.protected.paths=/bff/*,/light/v1/vessels/*
# Super-user paths of type /** are not supported
monitorfish.api.protected.super-user-paths=/bff/v1/beacon_malfunctions,/bff/v1/missions,/bff/v1/operational_alerts,/bff/v1/reportings,/bff/v1/vessels/risk_factors
monitorfish.api.protected.super-user-paths=/bff/v1/beacon_malfunctions,/bff/v1/missions,/bff/v1/operational_alerts,/bff/v1/reportings,/bff/v1/vessels/risk_factors,/bff/v1/control_objectives,/bff/v1/fleet_segments/backoffice,/bff/v1/fleet_segments/compute
monitorfish.api.protected.public-paths=/api/v1/authorization/management/*,/api/v1/beacon_malfunctions/*,/api/v1/mission_actions/*

###################
Expand Down
50 changes: 50 additions & 0 deletions infra/dev/keycloak/realm-monitor-dev.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
{
"realm": "monitor",
"enabled": true,
"clients": [
{
"clientId": "monitorfish",
"enabled": true,
"protocol": "openid-connect",
"redirectUris": [
"http://localhost:3000/*"
],
"webOrigins": [
"http://localhost:3000"
],
"publicClient": true
}
],
"users": [
{
"username": "user",
"email": "[email protected]",
"firstName": "User",
"lastName": "Fish",
"enabled": true,
"emailVerified": true,
"credentials": [
{
"type": "password",
"value": "fish",
"temporary": false
}
]
},
{
"username": "superuser",
"email": "[email protected]",
"firstName": "SuperUser",
"lastName": "Fish",
"enabled": true,
"emailVerified": true,
"credentials": [
{
"type": "password",
"value": "fish",
"temporary": false
}
]
}
]
}
2 changes: 2 additions & 0 deletions infra/docker/docker-compose.cypress.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,10 @@ services:
- FRONTEND_MONITORENV_URL=http://0.0.0.0:8081
- FRONTEND_OIDC_AUTHORITY=https://authentification.recette.din.developpement-durable.gouv.fr/authSAML/oidc/monitorfish
- FRONTEND_OIDC_CLIENT_ID=monitorfish
- MONITORFISH_OIDC_ENABLED=false
- FRONTEND_OIDC_ENABLED=false
- FRONTEND_OIDC_REDIRECT_URI=https://monitorfish.din.developpement-durable.gouv.fr
- FRONTEND_OIDC_LOGOUT_REDIRECT_URI=https://monitorfish.din.developpement-durable.gouv.fr
- FRONTEND_MONITORFISH_VERSION=
- FRONTEND_SENTRY_DSN=https://[email protected]/8
- FRONTEND_SENTRY_TRACING_ORIGINS=
Expand Down
Loading
Loading