diff --git a/src/main/js/controllers/hakutoiveidenMuokkaus.js b/src/main/js/controllers/hakutoiveidenMuokkaus.js index 55f1ed027..69280e68e 100644 --- a/src/main/js/controllers/hakutoiveidenMuokkaus.js +++ b/src/main/js/controllers/hakutoiveidenMuokkaus.js @@ -33,6 +33,7 @@ export default ['$scope', '$location', '$http', '$cookies', function($scope, $lo $scope.loading = false; $scope.application = new Hakemus(response.data); $scope.application.oiliJwt = response.oiliJwt; + $scope.application.migriJwt = response.migriJwt; $scope.application.token = token; $scope.application.isHakutoiveidenMuokkaus = true; const henkilotiedot = response.data.hakemus.answers.henkilotiedot; diff --git a/src/main/js/directives/application.html b/src/main/js/directives/application.html index 4257933b1..26c7b732d 100644 --- a/src/main/js/directives/application.html +++ b/src/main/js/directives/application.html @@ -76,7 +76,8 @@

{{application.haku.name }}

- +
diff --git a/src/main/js/directives/migri.html b/src/main/js/directives/migri.html index 33c71c555..dd6d9f83e 100644 --- a/src/main/js/directives/migri.html +++ b/src/main/js/directives/migri.html @@ -3,5 +3,13 @@ {{ localization('migri.otsikko') }}
-
+
+ {{localization('migri.linkki-teksti')}} +

+ {{justSomeToken}} {{migriToken}} +

+

+ {{parsedUrl}} +

+
diff --git a/src/main/js/directives/migri.js b/src/main/js/directives/migri.js index 2dbe13bb9..a3b7481e4 100644 --- a/src/main/js/directives/migri.js +++ b/src/main/js/directives/migri.js @@ -4,11 +4,23 @@ export default function () { return { restrict: 'E', scope: { - migri: '&' + migri: '&migri', + token: '@token' }, template: require('./migri.html'), link: function (scope, element, attrs) { + console.log('linking', scope); scope.localization = localize; + scope.justSomeToken = 'c d e f g' + scope.migriTokenParsed = scope.token || 'no token found'; + scope.constructUrl = function() { + const base = "https://opintopolkumigri.fi?token="; + const localized = scope.localization('migri.linkki-pohja'); + console.log("Getting migri url for base " + (localized || base) + ". Token: " + scope.migriTokenParsed); + scope.parsedUrl = (localized || base) + scope.migriTokenParsed; + return (localized || base) + scope.migriTokenParsed; + } + scope.constructUrl(); } } } diff --git a/src/main/js/interceptors/nonSensitiveHakemus.js b/src/main/js/interceptors/nonSensitiveHakemus.js index b65e13f29..0a847dc3b 100644 --- a/src/main/js/interceptors/nonSensitiveHakemus.js +++ b/src/main/js/interceptors/nonSensitiveHakemus.js @@ -28,6 +28,7 @@ export default ['$cookies', function HakemusInterceptor($cookies) { if (shouldAuthenticate(response.config) && response.data && response.data.jsonWebToken) { setBearerToken($cookies, response.data.jsonWebToken); response.oiliJwt = response.data.oiliJwt; + response.migriJwt = response.data.migriJwt; response.data = response.data.response } return response diff --git a/src/main/js/models/hakemus.js b/src/main/js/models/hakemus.js index fdff60db2..c621cdc46 100644 --- a/src/main/js/models/hakemus.js +++ b/src/main/js/models/hakemus.js @@ -27,6 +27,7 @@ export default class Hakemus { postOffice: json.hakemus.postOffice }; this.oiliJwt = null; + this.migriJwt = "abcdefg"; this.hakemusSource = json.hakemusSource; this.previewUrl = json.previewUrl; } @@ -149,10 +150,16 @@ export default class Hakemus { showMigriURL() { return _.chain(this.valintatulosHakutoiveet()).map(function(tulos) { + console.log("Show migri url?", tulos) return tulos.showMigriURL }).filter(function(k) {return k}).head().value() } + getMigriUrl(base) { + console.log("Getting migri url for base " + base + ". Token: " + this.migriJwt) + return base + this.migriJwt; + } + oiliUrl() { var oiliJwt = this.oiliJwt; return _.chain(this.valintatulosHakutoiveet()).map(function(tulos) { diff --git a/src/main/resources/oph-configuration/common.properties.template b/src/main/resources/oph-configuration/common.properties.template index d1c784f70..cb53a0dbe 100644 --- a/src/main/resources/oph-configuration/common.properties.template +++ b/src/main/resources/oph-configuration/common.properties.template @@ -19,6 +19,7 @@ host.virkailija={{host_virkailija}} host.oppija={{host_oppija}} omatsivut.crypto.aes.key={{omatsivut_crypto_aes_key}} +omatsivut.migri.crypto.hmac.key={{omatsivut_crypto_hmac_key}} omatsivut.crypto.hmac.key={{omatsivut_crypto_hmac_key}} cas.url=https://{{host_virkailija}}/cas diff --git a/src/main/resources/oph-configuration/dev-vars.yml b/src/main/resources/oph-configuration/dev-vars.yml index 0836ed266..0b7732dd1 100644 --- a/src/main/resources/oph-configuration/dev-vars.yml +++ b/src/main/resources/oph-configuration/dev-vars.yml @@ -31,6 +31,7 @@ mongodb_hakemus_password: "" omatsivut_cas_ticket_url: "http://localhost/cas/v1/tickets" omatsivut_crypto_aes_key: "akuankkaakuankka" omatsivut_crypto_hmac_key: "akuankkaakuankkaakuankkaakuankka" +omatsivut_migri_crypto_hmac_key: "roopeankkaroopeankkaroopeankkaro" omatsivut_haku_app_username: "" omatsivut_haku_app_password: "" omatsivut_authentication_service_username: "" diff --git a/src/main/resources/translations/en.json b/src/main/resources/translations/en.json index 84605f1bf..02a09a361 100644 --- a/src/main/resources/translations/en.json +++ b/src/main/resources/translations/en.json @@ -219,7 +219,8 @@ "migri": { "otsikko": "You can now apply for a residence permit", "ohje-teksti": "", - "linkki-teksti": "Click here to apply for the residence permit" + "linkki-teksti": "Click here to apply for the residence permit", + "linkki-pohja": "https://migri.fi/en/residence-permit-application-for-studies?token=" }, "emailNote": { diff --git a/src/main/resources/translations/fi.json b/src/main/resources/translations/fi.json index e6e3a362d..9a10c9be1 100644 --- a/src/main/resources/translations/fi.json +++ b/src/main/resources/translations/fi.json @@ -219,7 +219,8 @@ "migri": { "otsikko": "Voit nyt hakea oleskelulupaa", "ohje-teksti": "", - "linkki-teksti": "Siirry tästä oleskeluluvan hakemiseen" + "linkki-teksti": "Siirry tästä oleskeluluvan hakemiseen", + "linkki-pohja": "https://migri.fi/opiskelijan-oleskelulupahakemus?token=" }, "emailNote": { diff --git a/src/main/resources/translations/sv.json b/src/main/resources/translations/sv.json index 80aff6b76..1a72d4ea6 100644 --- a/src/main/resources/translations/sv.json +++ b/src/main/resources/translations/sv.json @@ -219,7 +219,8 @@ "migri": { "otsikko": "Du kan nu ansöka om uppehållstillstånd", "ohje-teksti": "", - "linkki-teksti": "Klicka här för att ansöka om uppehållstillstånd" + "linkki-teksti": "Klicka här för att ansöka om uppehållstillstånd", + "linkki-pohja": "https://migri.fi/sv/ansokan-om-uppehallstillstand-for-studier?token=" }, "emailNote": { diff --git a/src/main/scala/fi/vm/sade/omatsivut/config/ApplicationSettings.scala b/src/main/scala/fi/vm/sade/omatsivut/config/ApplicationSettings.scala index 7450d7f61..93d87c4d6 100644 --- a/src/main/scala/fi/vm/sade/omatsivut/config/ApplicationSettings.scala +++ b/src/main/scala/fi/vm/sade/omatsivut/config/ApplicationSettings.scala @@ -33,6 +33,7 @@ case class ApplicationSettings(config: Config) extends GroupEmailerSettings(conf val aesKey : String = config.getString("omatsivut.crypto.aes.key") val hmacKey : String = config.getString("omatsivut.crypto.hmac.key") + val hmacKeyMigri : String = config.getString("omatsivut.crypto.hmac.key") //Todo actually use a different secret for migri val oppijaBaseUrlEn = config.getString("oppija.base.url.en") val oppijaBaseUrlFi = config.getString("oppija.base.url.fi") diff --git a/src/main/scala/fi/vm/sade/omatsivut/security/JsonWebToken.scala b/src/main/scala/fi/vm/sade/omatsivut/security/JsonWebToken.scala index 68f0c7dc2..4fd71017d 100644 --- a/src/main/scala/fi/vm/sade/omatsivut/security/JsonWebToken.scala +++ b/src/main/scala/fi/vm/sade/omatsivut/security/JsonWebToken.scala @@ -11,6 +11,21 @@ import scala.util.{Failure, Success, Try} case class HakemusJWT(oid: Oid, answersFromThisSession: Set[AnswerId], personOid: Oid) case class OiliJWT(hakijaOid: Oid, expires: Long) +case class MigriJWT(hakijaOid: Oid, expires: Long) + +class MigriJsonWebToken(val secret: String) { + implicit val jsonFormats = formats(NoTypeHints) + + if (secret.getBytes.size * 8 < 256) throw new RuntimeException("(MIGRI) HMAC secret has to be at least 256 bits") + + val algo = JwtAlgorithm.HS256 + + def createMigriJWT(hakijaOid: String): String = { + val migriJwt = MigriJWT(hakijaOid, System.currentTimeMillis + (3600 * 2 * 1000)) //two hours expiry time + JwtJson4s.encode(write(migriJwt), secret, algo) + } +} + class JsonWebToken(val secret: String) { implicit val jsonFormats = formats(NoTypeHints) diff --git a/src/main/scala/fi/vm/sade/omatsivut/servlet/ApplicationsServlet.scala b/src/main/scala/fi/vm/sade/omatsivut/servlet/ApplicationsServlet.scala index ffa44f634..2e8f4a4b9 100644 --- a/src/main/scala/fi/vm/sade/omatsivut/servlet/ApplicationsServlet.scala +++ b/src/main/scala/fi/vm/sade/omatsivut/servlet/ApplicationsServlet.scala @@ -14,7 +14,7 @@ import fi.vm.sade.hakemuseditori.viestintapalvelu.{AccessibleHtml, Pdf} import fi.vm.sade.omatsivut.config.AppConfig import fi.vm.sade.omatsivut.config.AppConfig.AppConfig import fi.vm.sade.omatsivut.hakemuspreview.HakemusPreviewGeneratorComponent -import fi.vm.sade.omatsivut.security.{AuthenticationRequiringServlet, SessionService} +import fi.vm.sade.omatsivut.security.{AuthenticationRequiringServlet, JsonWebToken, MigriJsonWebToken, SessionService} import fi.vm.sade.omatsivut.vastaanotto.{Vastaanotto, VastaanottoComponent} import fi.vm.sade.utils.cas.{CasAuthenticatingClient, CasClient, CasParams} import org.http4s.client.blaze @@ -41,6 +41,8 @@ trait ApplicationsServletContainer { extends OmatSivutServletBase with JsonFormats with JacksonJsonSupport with AuthenticationRequiringServlet with HakemusEditoriUserContext { + private val migriJwt = new MigriJsonWebToken(appConfig.settings.hmacKeyMigri) + def user = Oppija(personOid()) private val hakemusEditori = newEditor(this) protected val applicationDescription = "Oppijan henkilökohtaisen palvelun REST API, jolla voi hakea ja muokata hakemuksia ja omia tietoja" @@ -67,14 +69,15 @@ trait ApplicationsServletContainer { } } + //Todo, tarvitaanko migritokenia tällä puolella lainkaan? get("/") { val oid = personOid() hakemusEditori.fetchByPersonOid(request, oid, Fetch) match { case FullSuccess(hakemukset) => - Map("allApplicationsFetched" -> true, "applications" -> hakemukset) + Map("allApplicationsFetched" -> true, "applications" -> hakemukset, "migriJwt" -> migriJwt.createMigriJWT(oid)) case PartialSuccess(hakemukset, exceptions) => exceptions.foreach(logger.warn(s"Failed to fetch all applications for oid $oid",_)) - Map("allApplicationsFetched" -> false, "applications" -> hakemukset) + Map("allApplicationsFetched" -> false, "applications" -> hakemukset, "migriJwt" -> migriJwt.createMigriJWT(oid)) case FullFailure(exceptions) => exceptions.foreach(logger.error(s"Failed to fetch applications for oid $oid", _)) throw exceptions.head diff --git a/src/main/scala/fi/vm/sade/omatsivut/servlet/NonSensitiveApplicationServlet.scala b/src/main/scala/fi/vm/sade/omatsivut/servlet/NonSensitiveApplicationServlet.scala index 4154d84b5..3fbccb416 100644 --- a/src/main/scala/fi/vm/sade/omatsivut/servlet/NonSensitiveApplicationServlet.scala +++ b/src/main/scala/fi/vm/sade/omatsivut/servlet/NonSensitiveApplicationServlet.scala @@ -14,7 +14,7 @@ import fi.vm.sade.hakemuseditori.viestintapalvelu.{AccessibleHtml, Pdf} import fi.vm.sade.omatsivut.NonSensitiveHakemusInfo.answerIds import fi.vm.sade.omatsivut.config.AppConfig.AppConfig import fi.vm.sade.omatsivut.oppijantunnistus.{ExpiredTokenException, InvalidTokenException, OppijanTunnistusComponent} -import fi.vm.sade.omatsivut.security.{HakemusJWT, JsonWebToken} +import fi.vm.sade.omatsivut.security.{HakemusJWT, JsonWebToken, MigriJsonWebToken} import fi.vm.sade.omatsivut.vastaanotto.{Vastaanotto, VastaanottoComponent} import fi.vm.sade.omatsivut.{NonSensitiveHakemus, NonSensitiveHakemusInfo, NonSensitiveHakemusInfoSerializer, NonSensitiveHakemusSerializer} import org.json4s._ @@ -29,7 +29,7 @@ sealed trait InsecureResponse { } case class InsecureHakemus(jsonWebToken: String, response: NonSensitiveHakemus) extends InsecureResponse -case class InsecureHakemusInfo(jsonWebToken: String, response: NonSensitiveHakemusInfo, oiliJwt: String = null) extends InsecureResponse +case class InsecureHakemusInfo(jsonWebToken: String, response: NonSensitiveHakemusInfo, oiliJwt: String = null, migriJwt: String = null) extends InsecureResponse trait NonSensitiveApplicationServletContainer { this: HakemusRepositoryComponent with @@ -44,6 +44,7 @@ trait NonSensitiveApplicationServletContainer { protected val applicationDescription = "Oppijan henkilökohtaisen palvelun REST API, jolla voi muokata hakemusta heikosti tunnistautuneena" private val hakemusEditori = newEditor(this) private val jwt = new JsonWebToken(appConfig.settings.hmacKey) + private val migriJwt = new MigriJsonWebToken(appConfig.settings.hmacKeyMigri) class UnauthorizedException(msg: String) extends RuntimeException(msg) class ForbiddenException(msg: String) extends RuntimeException(msg) @@ -152,10 +153,12 @@ trait NonSensitiveApplicationServletContainer { token <- jwtAuthorize hakemus <- fetchHakemus(token.oid, Some(token.personOid)) } yield { + val personOid = oppijanumerorekisteriService.henkilo(token.personOid).oid Ok(InsecureHakemusInfo( jwt.encode(token), new NonSensitiveHakemusInfo(hakemus, token.answersFromThisSession), - oiliJwt = jwt.createOiliJwt(oppijanumerorekisteriService.henkilo(token.personOid).oid) + oiliJwt = jwt.createOiliJwt(personOid), + migriJwt = migriJwt.createMigriJWT(personOid) )) }).get } @@ -184,13 +187,14 @@ trait NonSensitiveApplicationServletContainer { get("/applications/application/token/:token") { (for { metadata <- oppijanTunnistusService.validateToken(params("token")) - hakemus <- fetchHakemus(metadata.hakemusOid, metadata.personOid) + hakemus: HakemusInfo <- fetchHakemus(metadata.hakemusOid, metadata.personOid) } yield { + val personOid = oppijanumerorekisteriService.henkilo(hakemus.hakemus.personOid).oid Ok(InsecureHakemusInfo( jwt.encode(HakemusJWT(metadata.hakemusOid, Set(), hakemus.hakemus.personOid)), new NonSensitiveHakemusInfo(hakemus, Set()), - oiliJwt = jwt.createOiliJwt( - oppijanumerorekisteriService.henkilo(hakemus.hakemus.personOid).oid) + oiliJwt = jwt.createOiliJwt(personOid), + migriJwt = migriJwt.createMigriJWT(personOid) )) }).get }