-
Notifications
You must be signed in to change notification settings - Fork 0
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
base: main
Are you sure you want to change the base?
Changes from 13 commits
e8224f9
c3f9d34
68ea45f
862f9b5
f6031e4
22f004c
104d158
3c0661e
db6b906
7e18743
2bc85c4
aaec2b9
c2e7162
6daad69
d56d2b8
5d3b90e
6d8efaf
e7617fc
89dec98
86c7d68
f5e034c
bb09091
0bd6f10
2ab7fd7
395f370
44cb0b7
4336dd9
56b582a
5399a77
4052f22
20bfd02
0264754
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
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 | ||
|
||
|
@@ -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) { | ||
|
||
val LOG = LoggerFactory.getLogger(classOf[SecurityOperaatiot]) | ||
final val SECURITY_ROOLI_PREFIX_PATTERN = "^ROLE_" | ||
|
@@ -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!") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 = | ||
|
@@ -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] | ||
} |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.