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

OK-751 käyttöoikeuskäsittelyn tehostamista #84

Open
wants to merge 32 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 13 commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
e8224f9
OK-439 aikarajaus kantahakuun, parametrien välitys frontista bäkkäril…
marjakari Oct 3, 2024
c3f9d34
OK-439 fiksattu dev käyttäjän roolit, päivitetty datepicker
marjakari Oct 15, 2024
68ea45f
OK-439 suodatus aikavälillä toimivaksi, korvattu date-fns-tz dayjs:ll…
marjakari Oct 23, 2024
862f9b5
OK-439 katselmointihuomioita ja typescript-herjojen ohitus
marjakari Oct 25, 2024
f6031e4
OK-439 korjattu asiointikielen väärä polku
marjakari Oct 25, 2024
22f004c
OK-439 pakitettu build.yml säätö
marjakari Oct 25, 2024
104d158
OK-652 setup next env kokeilu
marjakari Nov 14, 2024
3c0661e
OK-652 siivoiluja
marjakari Nov 15, 2024
db6b906
debug-lokitusta
marjakari Nov 18, 2024
7e18743
OK-652 dekoodataan hakustring
marjakari Nov 18, 2024
2bc85c4
OK-751 käyttäjän oikeudet sessioon WIP
marjakari Nov 27, 2024
aaec2b9
OK-751 käyttöoikeuksien sessiotallennukseen yksikkötestejä, asiointik…
marjakari Nov 27, 2024
c2e7162
OK-751 tarkistetaan onko tulllut uusia käyttöoikeuksia kantaan ja päi…
marjakari Nov 28, 2024
6daad69
OK-751 käsitellään käyttäjän käyttöoikeuksista vain ne mitä palvelust…
marjakari Dec 4, 2024
d56d2b8
integraatiotesti raportointi-apille
marjakari Dec 5, 2024
5d3b90e
OK-443 korjattu client-kirjaston login-polku ja täydennetty integraat…
marjakari Dec 12, 2024
6d8efaf
OK-443 päivitetty versio
marjakari Dec 12, 2024
e7617fc
OK-443 päivitetty versio kaikkiin aliprojektihin
marjakari Dec 12, 2024
89dec98
OK-443 julkaistaan github ackagesissa kaikki tarvittavat moduulit
marjakari Dec 12, 2024
86c7d68
OK-443 maven syntaksi kirjasto-deployhin
marjakari Dec 12, 2024
f5e034c
OK-443 deployataan toistaiseksi kaikki
marjakari Dec 12, 2024
bb09091
OK-443 maven flatten plugin kirjastoon
marjakari Dec 12, 2024
0bd6f10
OK-443 snapshot-version kovakoodaus pois ja muuttuja tilalle
marjakari Dec 12, 2024
2ab7fd7
OK-443 päivitetty client-kirjaston readme ja käyttöoikeusattribuutit …
marjakari Dec 16, 2024
395f370
OK-443 kokeillaan ilman flatten-pluginia
marjakari Dec 16, 2024
44cb0b7
OK-443 kokeillaan ilman revision-konffia pomissa
marjakari Dec 16, 2024
4336dd9
OK-443 flatten plugin takaisin
marjakari Dec 16, 2024
56b582a
OK-443 revisio järkevämmin takaisin, client-kirjastossa käyttöoikeusr…
marjakari Dec 16, 2024
5399a77
OK-443 versionnosto
marjakari Dec 16, 2024
4052f22
OK-443 clientiin käyttöoikeusrajoituksille builder ja testin päivitys
marjakari Dec 16, 2024
20bfd02
OK-443 static metodit pois java interfaceista
marjakari Dec 17, 2024
0264754
OK-443 readme
marjakari Dec 17, 2024
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
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package fi.oph.viestinvalitys.raportointi.configuration

import com.zaxxer.hikari.HikariDataSource
import fi.oph.viestinvalitys.raportointi.App
import fi.oph.viestinvalitys.raportointi.resource.RaportointiAPIConstants
import fi.oph.viestinvalitys.util.DbUtil
import fi.vm.sade.javautils.kayttooikeusclient.OphUserDetailsServiceImpl
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import fi.oph.viestinvalitys.util.ConfigurationUtil
import fi.vm.sade.javautils.nio.cas.{CasClient, CasClientBuilder}
import org.asynchttpclient.RequestBuilder
import org.slf4j.LoggerFactory
import upickle.default.*

import java.util.concurrent.TimeUnit
import scala.concurrent.Await
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ class OrganisaatioCache {

val childOidsLoader = new CacheLoader[String, Response[String]] {
def load(oid: String): Response[String] =
LOG.info(s"Ladataan lapsiorganisaatio-cache oidille $oid")
val uri: Uri = uri"https://virkailija.$opintopolkuDomain/organisaatio-service/api/$oid/childoids?$queryParams"
quickRequest
.headers(headers)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ class OrganisaatioService {
val LOG = LoggerFactory.getLogger(classOf[OrganisaatioService])

def getAllChildOidsFlat(oid: String): Set[String] =
LOG.info(s"Haetaan lapsiorganisaatiot cachesta oidille $oid")
if (!OrganisaatioOid.isValid(oid))
LOG.error(s"Organisaation oid $oid on virheellinen")
throw new RuntimeException(s"Organisaation oid $oid on virheellinen")
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
package fi.oph.viestinvalitys.raportointi.resource

import fi.oph.viestinvalitys.raportointi.integration.{ONRService}
import fi.oph.viestinvalitys.raportointi.integration.ONRService
import fi.oph.viestinvalitys.raportointi.security.SecurityOperaatiot
import io.swagger.v3.oas.annotations.Operation
import io.swagger.v3.oas.annotations.responses.ApiResponse
import io.swagger.v3.oas.annotations.tags.Tag
import jakarta.servlet.http.{HttpServletRequest, HttpSession}
import org.slf4j.LoggerFactory
import org.springframework.http.{HttpStatus, MediaType, ResponseEntity}
import org.springframework.web.bind.annotation.{GetMapping, RequestMapping, RestController}
Expand All @@ -27,8 +28,10 @@ class HenkiloResource {
responses = Array(
new ApiResponse(responseCode = "200", description = "Palauttaa asiointikielen"),
))
def getAsiointikieli() = {
def getAsiointikieli(request: HttpServletRequest) = {
LOG.info("Haetaan asiointikieli")
val session: HttpSession = request.getSession(false)
LOG.warn(s"sessio: ${session}")
val securityOperaatiot = new SecurityOperaatiot
val result = OnrService.haeAsiointikieli(securityOperaatiot.getIdentiteetti())
result match
Expand Down

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package fi.oph.viestinvalitys.raportointi.security

import fi.oph.viestinvalitys.business.Kayttooikeus
import fi.oph.viestinvalitys.business.{KantaOperaatiot, Kayttooikeus}
import fi.oph.viestinvalitys.raportointi.integration.OrganisaatioService
import fi.oph.viestinvalitys.raportointi.security.SecurityConstants.OPH_ORGANISAATIO_OID
import fi.oph.viestinvalitys.raportointi.security.SecurityConstants.{OPH_ORGANISAATIO_OID, SESSION_ATTR_KAYTTOOIKEUDET, SESSION_ATTR_KAYTTOOIKEUSTUNNISTEET, SESSION_ATTR_UUSIN_KAYTTOOIKEUSTUNNISTE}
import fi.oph.viestinvalitys.util.DbUtil
import jakarta.servlet.http.HttpSession
import org.slf4j.LoggerFactory
import org.springframework.security.core.context.SecurityContextHolder

Expand All @@ -24,12 +26,18 @@ object SecurityConstants {

final val LAHETYS_ROLES = Set(SECURITY_ROOLI_LAHETYS_OIKEUS, SECURITY_ROOLI_PAAKAYTTAJA_OIKEUS)
final val KATSELU_ROLES = Set(SECURITY_ROOLI_KATSELU_OIKEUS, SECURITY_ROOLI_PAAKAYTTAJA_OIKEUS)

final val SESSION_ATTR_KAYTTOOIKEUDET = "kayttooikeudet"
final val SESSION_ATTR_KAYTTOOIKEUSTUNNISTEET = "kayttooikeustunnisteet"
final val SESSION_ATTR_UUSIN_KAYTTOOIKEUSTUNNISTE = "uusintunniste"
}

class SecurityOperaatiot(
getOikeudet: () => Seq[String] = () => SecurityContextHolder.getContext.getAuthentication.getAuthorities.asScala.map(a => a.getAuthority).toSeq,
getUsername: () => String = () => SecurityContextHolder.getContext.getAuthentication.getName(),
organisaatioClient: OrganisaatioService = OrganisaatioService) {
getOikeudet: () => Seq[String] = () => SecurityContextHolder.getContext.getAuthentication.getAuthorities.asScala.map(a => a.getAuthority).toSeq,
getUsername: () => String = () => SecurityContextHolder.getContext.getAuthentication.getName(),
organisaatioClient: OrganisaatioService = OrganisaatioService,
kantaOperaatiot: KantaOperaatiot = new KantaOperaatiot(DbUtil.database),
optionalHttpSession: Option[HttpSession] = None) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Miksi sessio on optionaalinen, eikö olisi yksinkertaisempaa vaatia se aina?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

En siinä kohti halunnut uusia joka kohtaa missä luodaan SecurityOperaatiot-intanssi niin oli helpompaa jättää se optionaaliseksi, kun ihan joka kohdassa missä sitä käytettiin ei tarvittu käyttöoikeuksia eikä siis myöskään sessiota vaan esim käyttäjän henkilö-oidin kysely. Ehkä yksinkertaistaisi jos sen passaisi silti aina.


val LOG = LoggerFactory.getLogger(classOf[SecurityOperaatiot])
final val SECURITY_ROOLI_PREFIX_PATTERN = "^ROLE_"
Expand All @@ -45,19 +53,57 @@ class SecurityOperaatiot(
})
.toSet
}

// säilytetään käyttöoikeudet sessiossa
// koska niiden parsiminen aliorganisaatiotasolle kestää jos on runsaasti aliorganisaatiotasoja
private lazy val kayttajanOikeudet: Set[Kayttooikeus] = {
val pk = onPaakayttaja()
if(onPaakayttaja())
kayttajanCasOikeudet // ei tarvitse mapata kaikkia lapsiorganisaatioita
else
val lapsioikeudet = kayttajanCasOikeudet
.filter(kayttajanOikeus => kayttajanOikeus.organisaatio.isDefined)
.map(kayttajanOikeus =>
organisaatioClient.getAllChildOidsFlat(kayttajanOikeus.organisaatio.get)
.map(o => Kayttooikeus(kayttajanOikeus.oikeus, Some(o)))
).flatten
kayttajanCasOikeudet ++ lapsioikeudet
optionalHttpSession match {
case Some(n) if optionalHttpSession.get.getAttribute(SESSION_ATTR_KAYTTOOIKEUDET) != null =>
LOG.warn("oikat sessiosta!")
parseTypedKayttooikeusSetFromSession(optionalHttpSession.get, SESSION_ATTR_KAYTTOOIKEUDET).getOrElse(Set.empty)
case _ =>
LOG.warn("parsitaan oikat!")
LOG.info("Haetaan käyttöoikeuksien organisaatioiden aliorganisaatiot")
val lapsioikeudet = kayttajanCasOikeudet
.filter(kayttajanOikeus => kayttajanOikeus.organisaatio.isDefined)
.map(kayttajanOikeus =>
organisaatioClient.getAllChildOidsFlat(kayttajanOikeus.organisaatio.get)
.map(o => Kayttooikeus(kayttajanOikeus.oikeus, Some(o)))).flatten
if(optionalHttpSession.isDefined)
optionalHttpSession.get.setAttribute(SESSION_ATTR_KAYTTOOIKEUDET, kayttajanCasOikeudet ++ lapsioikeudet)
kayttajanCasOikeudet ++ lapsioikeudet
}
}

// säilytetään käyttöoikeustunnisteet sessiossa
// ja virkistetään kannasta vain jos on tullut uusia sen jälkeen kun tunnisteet laitettiin sessioon
private lazy val kayttajanKayttooikeustunnisteet: Option[Set[Int]] = {
val pk = onPaakayttaja()
if (onPaakayttaja())
Option.empty
else
optionalHttpSession match {
case None =>
LOG.warn("ei sessiota, oikkatunnisteet kannasta!")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Liittyen aikaisempaan kommenttiin, onko tämä skeenario jota halutaan/pakko tukea?

Option.apply(kantaOperaatiot.getKayttooikeusTunnisteet(kayttajanOikeudet.toSeq))
case Some(n) if optionalHttpSession.get.getAttribute(SESSION_ATTR_KAYTTOOIKEUSTUNNISTEET) != null
&& eiUusiaTunnisteitaKannassa(optionalHttpSession.get, kantaOperaatiot) =>
LOG.warn("oikkatunnisteet sessiosta!")
parseTypedTunnisteAttributeFromSession(optionalHttpSession.get, SESSION_ATTR_KAYTTOOIKEUSTUNNISTEET)
case _ =>
LOG.warn("oikkatunnisteet kannasta ja laitetaan sessioon!")
val tunnisteet = kantaOperaatiot.getKayttooikeusTunnisteet(kayttajanOikeudet.toSeq)
val uusinTunniste = kantaOperaatiot.getUusinKayttooikeusTunniste()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

koska tunnisteiden ja uusimman tunnisteen haku ei tapahtu transaktionaalisesti, voi periaatteessa näiden kahden välissä kantaan tulla uusia tunnisteita, getKayttooikeusTunnisteet voisi palauttaa transaktionaalisesti tuplen.

optionalHttpSession.get.setAttribute(SESSION_ATTR_KAYTTOOIKEUSTUNNISTEET, tunnisteet)
optionalHttpSession.get.setAttribute(SESSION_ATTR_UUSIN_KAYTTOOIKEUSTUNNISTE, uusinTunniste)
Some(tunnisteet)
}
}

val identiteetti = getUsername()

def getIdentiteetti(): String =
Expand Down Expand Up @@ -93,9 +139,35 @@ class SecurityOperaatiot(

def getKayttajanOikeudet(): Set[Kayttooikeus] = kayttajanOikeudet

def getKayttajanKayttooikeustunnisteet(): Option[Set[Int]] = kayttajanKayttooikeustunnisteet

/**
* Palauttaa käyttäjän käyttöoikeuksien organisaatiot ilman lapsihierarkiaa
*/
def getCasOrganisaatiot(): Set[String] =
kayttajanCasOikeudet.filter(kayttooikeus => kayttooikeus.organisaatio.isDefined).map(ko => ko.organisaatio.get)

def parseTypedTunnisteAttributeFromSession(session: HttpSession, attributeName: String): Option[Set[Int]] = {
Option(session.getAttribute(attributeName)) match {
case Some(value: Set[_]) =>
// Safely cast elements to Int, filter out invalid ones
Some(value.collect { case i: Int => i })
case _ =>
None
}
}

def parseTypedKayttooikeusSetFromSession(session: HttpSession, attributeName: String): Option[Set[Kayttooikeus]] = {
Option(session.getAttribute(attributeName)) match {
case Some(value: Set[_]) =>
// Safely cast elements to Kayttooikeus, filter out invalid ones
Some(value.collect { case i: Kayttooikeus => i })
case _ =>
None
}
}

def eiUusiaTunnisteitaKannassa(session: HttpSession, kantaOperaatiot: KantaOperaatiot): Boolean =
val uusin = kantaOperaatiot.getUusinKayttooikeusTunniste()
uusin == session.getAttribute(SESSION_ATTR_UUSIN_KAYTTOOIKEUSTUNNISTE).asInstanceOf[Int]
}
Loading